如何使用 LEFT JOIN 创建 JPA NamedQuery

Posted

技术标签:

【中文标题】如何使用 LEFT JOIN 创建 JPA NamedQuery【英文标题】:How to create JPA NamedQuery with LEFT JOIN 【发布时间】:2017-10-13 14:33:31 【问题描述】:

我有两个实体:汽车和预订。我想用 LEFT JOIN 创建命名查询。我试图这样做,就像这里描述的那样 How to create JPA query with LEFT OUTER JOIN 但它不起作用。你知道我的查询有什么问题吗?我想展示具有 NULL 预订的汽车。无论如何,即使使用 JOIN 它也不起作用。启动应用程序后出现错误:

Caused by: org.hibernate.HibernateException: Errors in named queries: Car.findAll
    at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:495) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:444) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:879) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
    ... 22 common frames omitted

原则上我想实现这个在 mysql 中有效的查询

SELECT distinct * FROM car c LEFT JOIN reservation r ON c.id = r.car_id WHERE c.producer='producer' AND c.model='model' AND c.type='type' 
AND (r.date_of_rent < 'date1' AND r.date_of_return < 'date1') OR (r.date_of_rent > 'date2') OR r.date_of_rent IS NULL;

汽车实体

import java.io.Serializable;
import java.util.List;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;

@Entity
@NamedQuery(name = "Car.findAll", query = "SELECT c FROM Car c LEFT JOIN c.reservation r WHERE c.producer=:producer "
        + "AND c.type=:type AND c.dailyPrice=:dailyPrice")
public class Car implements Serializable 
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String producer;
    private String model;
    private int seatsNumber;
    private String type;
    private String registrationNumber;
    private double dailyPrice;
    private String description;
    @OneToMany(mappedBy = "car")
    private List<Reservation> reservations;

预订实体

import java.io.Serializable;
import java.sql.Date;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

@Entity
public class Reservation implements Serializable 
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @ManyToOne
    private User user;
    @ManyToOne
    private Car car;
    private Date dateOfRent;
    private Date dateOfReturn;

非常感谢您的帮助。

更新

问题解决了。查询应该是这样的

import java.io.Serializable;
import java.util.List;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;

@Entity
@NamedQuery(name = "Car.findAll", query = "SELECT DISTINCT c FROM Car c LEFT JOIN c.reservations r WHERE "
        + "c.type=:type AND c.dailyPrice<=:dailyPrice AND ((r.dateOfRent < :dateOfRent AND r.dateOfReturn < :dateOfRent) OR "
        + "(r.dateOfRent > :dateOfReturn) OR (r.dateOfRent IS NULL))")
public class Car implements Serializable 
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String producer;
    private String model;
    private Integer seatsNumber;
    private String type;
    private String registrationNumber;
    private Double dailyPrice;
    private String description;
    @OneToMany(mappedBy = "car")
    private List<Reservation> reservations;

【问题讨论】:

请补充问题:为什么需要左连接? “它不起作用”?那应该是什么意思?你有例外吗?它运行一些 SQL(您不发布),但您得到的结果与您期望的不同?什么都没有发生? 我发布了这个查询的错误以及我想要实现的查询。 @bartekms274 最好添加带有错误描述的堆栈跟踪部分。 Errors in named queries: Car.findAll 并没有说明很多。我也用那个错误更新了我的答案。 【参考方案1】:
SELECT c FROM Car c LEFT JOIN c.reservation r WHERE c.producer=:producer "
        + "AND c.type=:type AND c.dailyPrice=:dailyPrice

这个查询有错误c.reservation需要改成c.reservations

我想显示预订为 NULL 的汽车。

你不能这样做。尝试从这个查询开始:

select c from Car c where not exists (
    select r.id from Reservation r where r.car.id = c.id
)

【讨论】:

以上是关于如何使用 LEFT JOIN 创建 JPA NamedQuery的主要内容,如果未能解决你的问题,请参考以下文章

JPA Left Join IS NULL条件不起作用

如何根据列值与没有关联的表进行 LEFT JOIN

mysql where not in to left outer join

如何创建有条件的 LEFT JOIN?

如何使用 $lookup MongoDB 进行 LEFT JOIN

如何使用 JPA 和 Hibernate 删除带有 JOIN 的实体