【问题标题】:JPA CriteriaQuery join only entities which match the CriteriaJPA CriteriaQuery 仅加入符合条件的实体
【发布时间】:2018-04-13 18:39:00
【问题描述】:

我一直在编写代码来构建条件查询以进行条件连接。但它并不正确。请考虑以下示例:

我有 2 个实体 OwnerCarOwnerCarOneToMany 关系。

代码Owner 实体有ListCars。(使用@OneToManyFetchType.LAZY

所有者.java:

@Entity
public class Owner {

    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE)
    private int id;
    private String name;
    private String email;

    @OneToMany(mappedBy="owner",fetch=FetchType.LAZY)
    private List<Car>  cars;

    ...
}

汽车.java

@Entity
public class Car{

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private int id;
    private String manufacturer;
    private String regnumber;

    @ManyToOne
    @JoinColumn(name="ownerid")
    private Owner owner;
    ...
} 

现在我的要求很简单,我想获得所有 TESLA 汽车的车主。 以下代码适用于此:

CriteriaQuery<Owner> cq = cb.createQuery(Owner.class);
Root<Owner> rootowner = cq.from(Owner.class);
rootowner.fetch("cars");

cq.distinct(true);

Join<Owner, Car> carjoin= rootowner.join(Owner_.cars);
Expression<String> carmanExp = carjoin.get(Car_.manufacturer);
Predicate p = cb.like(carmanExp, "TESLA");
cq.where(p);

TypedQuery<Owner> tq = em.createQuery(cq);

现在我的要求是,如果Owner 拥有两辆汽车,一辆是特斯拉,另一辆是沃尔沃。我希望Owner 实体应该只包含TESLA

我该怎么做?

【问题讨论】:

  • 您正在选择 Owner 对象,如果 Owner 对象有这 2 辆汽车,那么当加载该对象时,它将有这 2 辆汽车。您将不会返回半个 Owner 对象。曾经
  • 但是当你运行一个普通的 SQL JOIN 查询 SELECT * FROM owner as o JOIN car as c on c.ownerid=o.id WHERE c.manufacturer='TESLA'; 它只返回一个元组。如果我们可以使用普通的旧 SQL 而不是 JPA,那么 JPA 对 SQL 或 JDBC 有什么优势?
  • 如果Owner JOHN 有 2 辆汽车,则返回为 Owner JOHN 的对象将始终有 2 辆汽车,因为 JOHN 有 2 辆汽车!这就是 O-O 的工作原理。如果您想执行平面 SQL 查询并将它们操作到仅包含部分信息的对象中,那就去吧,但是 JPA 是为 O-O 设计的,对象具有身份和关系。
  • 但是如果我使用 JPQL 作为TypedQuery&lt;Owner&gt; tq = em.createQuery("SELECT o FROM Owner o JOIN FETCH o.cars c WHERE c.manufacturer='TESLA'",Owner.class); 运行相同的查询,这将给我Owner 只有一辆车的对象。 O-O 在这里效果很好。我所需要的只是Criteria API 中这个 JPQL 的等价物。我知道可以这样做,因为我听说有人已经这样做了,但我现在无法询问。
  • 您的“正常”SQL 查询仍会为所有者返回多个结果 - 每辆特斯拉对应一行。但请注意,您的 SQL 查询关注的是汽车,而不是车主。在您的 JPA 示例中,您将获得完整的 Owner 实例并忽略汽车。您必须记住,在 JPA 中,查询条件仅用于选择返回的结果对象,而不是它们的构建方式。构建对象是基于您的映射,而不是您的查询,因此始终需要 owner.getCars 关系来根据映射反映数据库中的实际内容。

标签: java jpa eclipselink criteria criteriaquery


【解决方案1】:

您不能在简单的 JPA 查询中即时执行您所要求的操作,因为这是对 JPA 实体的操作,它不再代表数据库中的内容。换句话说,当 JPA 将仅引用特斯拉的所有者返回给您时,您希望它与现在已删除的沃尔沃在与数据库同步时做什么?

在您的情况下,最简单的解决方案是只查询您想要的汽车,因为它们引用了车主。如果车主可能拥有两个或更多特斯拉,您会得到重复的结果 - 您可以通过自己创建车主到汽车的地图以及结果来解决这个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-16
    • 2015-04-28
    • 2020-11-30
    • 1970-01-01
    • 2015-04-07
    • 2015-05-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多