如何使用Hibernate Criteria实现跨两表的OR查询?
跨表匹配
cdDocumentoIdentificativo的Criteria查询实现 先明确你的问题核心
你需要基于cdDocumentoIdentificativo字段,查询主实体中关联的Owners表或Sellers表里Person记录匹配该字段的所有条目。先指出你两次尝试的问题:
- 第一种尝试:子查询的关联逻辑混乱,别名使用错误,且条件用了
isNotNull而非字段匹配,完全偏离需求。 - 第二种尝试:属性路径错误(比如
owner.own.person这种嵌套逻辑不对),且硬编码了字符串常量,没有使用实际的过滤值。
正确实现方式(分两种场景)
假设你的主查询实体是MainEntity(比如订单、合同这类关联了Owner和Seller的业务实体),且MainEntity与Owner、Seller是一对多或多对多关联,Owner/Seller都关联了Person实体,Person包含cdDocumentoIdentificativo字段。
方式1:直接关联+OR条件查询
这是最直观的方式,通过创建别名关联到Person表,然后组合两个匹配条件:
String docId = (String) this.getFiltros().get("cdDocumentoIdentificativo"); if (docId != null && !docId.isEmpty()) { // 为Owner关联的Person创建别名 query.createAlias("owners", "own"); query.createAlias("own.person", "ownerPerson"); // 为Seller关联的Person创建别名 query.createAlias("sellers", "sell"); query.createAlias("sell.person", "sellerPerson"); // 组合OR条件:匹配Owner的Person或Seller的Person的cdDocumentoIdentificativo Criterion ownerMatch = Restrictions.eq("ownerPerson.cdDocumentoIdentificativo", docId); Criterion sellerMatch = Restrictions.eq("sellerPerson.cdDocumentoIdentificativo", docId); query.add(Restrictions.or(ownerMatch, sellerMatch)); }
注意:如果主实体与Owner/Seller是一对多关联,可能需要使用左连接模式避免数据丢失:
query.createAlias("owners", "own", JoinType.LEFT_OUTER_JOIN); query.createAlias("sellers", "sell", JoinType.LEFT_OUTER_JOIN);
方式2:子查询+EXISTS条件
如果不想直接关联多张表(避免笛卡尔积),可以用子查询分别判断Owner或Seller是否存在匹配记录:
String docId = (String) this.getFiltros().get("cdDocumentoIdentificativo"); if (docId != null && !docId.isEmpty()) { // 子查询1:查询匹配cdDocumentoIdentificativo的Owner对应的主实体ID DetachedCriteria ownerSubquery = DetachedCriteria.forClass(Owner.class, "own"); ownerSubquery.createAlias("own.person", "p"); ownerSubquery.add(Restrictions.eq("p.cdDocumentoIdentificativo", docId)); ownerSubquery.setProjection(Projections.property("own.mainEntity.id")); // 假设Owner关联主实体的字段是mainEntity // 子查询2:查询匹配cdDocumentoIdentificativo的Seller对应的主实体ID DetachedCriteria sellerSubquery = DetachedCriteria.forClass(Seller.class, "sell"); sellerSubquery.createAlias("sell.person", "p"); sellerSubquery.add(Restrictions.eq("p.cdDocumentoIdentificativo", docId)); sellerSubquery.setProjection(Projections.property("sell.mainEntity.id")); // 主查询添加OR条件:主实体ID存在于任一子查询结果中 query.add(Restrictions.or( Subqueries.propertyIn("id", ownerSubquery), Subqueries.propertyIn("id", sellerSubquery) )); }
关键注意点
- 确保实体类的关联映射正确(比如
Owner类中person字段的@ManyToOne/@OneToOne注解,MainEntity中owners/sellers的@OneToMany注解)。 - 属性路径必须严格对应实体类的字段名,比如
own.person对应的是Owner类中名为person的属性,而非数据库表字段名。 - 过滤值要使用变量
docId,而非硬编码的字符串"cdDocumentoIdentificativo"。
内容的提问来源于stack exchange,提问作者Imrik
相关产品推荐
相关产品推荐

