如何使CriteriaBuilder加入自定义“on”条件?

问题描述 投票:20回答:5

我想使用CriteriaBuilder在我加入2个表的地方进行查询。在MySQL中,我想要的查询看起来像这样:

SELECT * FROM order
LEFT JOIN item
ON order.id = item.order_id
AND item.type_id = 1

我想获得所有订单,如果他们有#1类型的商品,我想加入这个商品。但是,如果没有找到#1类型的项目,我仍然想要获得订单。我无法弄清楚如何使用CriteriaBuilder进行此操作。我所知道的是:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Order> cq = cb.createQuery(Order.class);
Root<Order> order = cq.from(Order.class);
Join<Order, Item> item = order.join(Order_.itemList, JoinType.LEFT);
Join<Item, Type> type = order.join(Item_.type, JoinType.LEFT);
cq.select(order);
cq.where(cb.equal(type.get(Type_.id), 1));

此查询已中断,因为它在MySQL中产生类似的结果:

SELECT * FROM order
LEFT JOIN item
ON order.id = item.order_id
WHERE item.type_id = 1

结果将只包含类型为#1的订单。没有订单被排除在外。如何使用CriteriaBuilder创建第一个示例中的查询?

jpa jpa-2.0 criteria-api
5个回答
14
投票

有可能使用on方法Join<Z, X> on(Predicate... restrictions);

方法如下:

Root<Order> order = cq.from(Order.class);
Join<Order, Item> item = order.join(Order_.itemList, JoinType.LEFT);
item.on(cb.equal(item.get(Item_.type), 1));

1
投票

我认为这与本期提出的问题相同。看起来在CriteriaBuilder中是不可能的。它可以在Hibernate Criteria API中使用,但这可能对您没有帮助。

JPA Criteria API: Multiple condition on LEFT JOIN


0
投票

我知道这个问题花了很长时间,但最近有一个问题,我从Oracle论坛找到了这个解决方案,我复制并粘贴,以防链接不再可用。

MiguelChillitupaArmijos 29-abr-2011 1:41(en respuesta a 840578)认为你应该使用类似的东西:

em.createQuery("SELECT DISTINCT e.Id" +
                    " from Email e " +
                    " left join e.idEmailIn e2 *with* e2.responseType = 'response'" +
                    "     where e.type = 'in' and e.responseMandatory = true").getSingleResult(); 

这是链接。

JPA Criteria : LEFT JOIN with an AND condition


0
投票

如果您使用带有JPA 2.0的Hibernate 3.6,则有一种解决方法。这不是更好的解决方案,但它对我来说非常适合。

我用@Where hibernate annotation复制了实体。这意味着每次你使用这个实体的连接时,hibernate都会在生成的SQL的join语句中添加额外的条件。

例如,最初我们有以下示例:

@Entity
@Table(name = "PERSON")
public class Person {

    @Id
    @Column(name = "PERSON_ID")
    private Long id;

    @Id
    @Column(name = "PERSON_NAME")
    private String name;

   @OneToMany(mappedBy = "person", fetch = FetchType.LAZY)
   private Set<Address> addresses;

}

@Entity
@Table(name = "ADDRESS")
public class Address {

    @Id
    @Column(name = "ADDRESS_ID")
    private Long id;

    @Id
    @Column(name = "ADDRESS_STREET")
    private String street;

   @ManyToOne
   @JoinColumn(name = "PERSON_ID")
    private Person person;

}

为了在条件Join上添加额外条件,我们需要复制Address @Entity映射,添加@Where注释@Where(clause =“ADDRESS_TYPE_ID = 2”)。

@Entity
@Table(name = "ADDRESS")
@Where(clause = " ADDRESS_TYPE_ID = 2")
public class ShippingAddress {

    @Id
    @Column(name = "ADDRESS_ID")
    private Long id;

    @Id
    @Column(name = "ADDRESS_STREET")
    private String street;

   @OneToOne
   @JoinColumn(name = "PERSON_ID")
    private Person person;

}

此外,我们需要为新实体添加重复的映射关联。

@Entity
@Table(name = "PERSON")
public class Person {

    @Id
    @Column(name = "PERSON_ID")
    private Long id;

    @Id
    @Column(name = "PERSON_NAME")
    private String name;

   @OneToMany(mappedBy = "person", fetch = FetchType.LAZY)
   private Set<Address> addresses;

   @OneToOne(mappedBy = "person")
   private ShippingAddress shippingAddress;

}

最后,您可以在条件中使用与此特定实体的联接:

PersonRoot.join(Person_.shippingAddress, JoinType.LEFT);

Hibernate Snippet SQL应该是这样的:

 left outer join
        address shippingadd13_ 
            on person11_.person_id=shippingadd13_.person_id 
            and (
                shippingadd13_.ADDRESS_TYPE_ID = 2 
            ) 

0
投票

Hibernate 4.3版本支持ON子句,任何人都知道在使用ON子句进行外连接时,附加自定义条件的参数索引与现有映射过滤器的索引之间是否存在参数索引问题?

使用下面的Person实体类作为示例,假设我添加此过滤器以限制地址类型,并且启用过滤器以填充IN子句。当我添加ON子句的附加条件(例如使用'street'列)部分时,IN子句的参数索引将导致问题[2]。是已知问题吗?

[1] @Filter(name =“addressTypes”,condition =“ADDRESS_TYPE in(:supportedTypes)”)

[2]引起:ERROR 22018:BIGINT类型的字符串格式无效。私人集合地址;

© www.soinside.com 2019 - 2024. All rights reserved.