为基于oneTomany关系的查询编写queryDSL谓词查询

时间:2016-11-02 11:45:47

标签: mysql spring-data querydsl

我正在使用spring-data,QueryDSL和MySQL。

问题的主要目的是知道如何以queryDSL方式进行这样的查询。给出的例子只是一个提供想法的简单例子。

比如说,有两个表Employee和Certificate。两者之间的关系是ONE(Employee)到MANY(Certificate)

以下是表格,

Employee (id, first_name, last_name);
Certificate (id, name, date, fk_emp);

的QueryDSL谓词应该是什么
  

返回名称中包含的所有员工(在first_name和last_name中)以及在2014年12月22日至2015年12月22日期间获得认证的结果

我尝试了但是无法了解如何以QueryDSL方式迭代每个员工的每个证书并返回员工列表。

您的回复将受到高度赞赏!!

修改

以下是实体,

@Entity
@Table(name = "EMPLOYEE")
class Employee {
  @Id
  @Column(name = "ID")
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;

  @Column(name = "FIRST_NAME")
  private String firstName;

  @Column(name = "LAST_NAME")
  private String lastName;

  @OneToMany(mappedBy = "employee", cascade = CascadeType.ALL)
  private List<Certificate> certificates = new ArrayList<>();
}

@Entity
@Table(name = "CERTIFICATE")
class Certificate {
  @Id
  @Column(name = "ID")
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;

  @Column(name = "CERTIFICATE_NAME")
  private String certificateName;

  @Column(name = "DATE")
  private Date date;

  @ManyToOne
  @JoinColumn(name = "REF_EMPLOYEE")
  private Employee employee;
}

2 个答案:

答案 0 :(得分:8)

最简单的方法是将其反转并查询证书,这很简单,然后您可以从返回的证书中获取员工。

QCertificate certificate = QCertificate.certificate;
BooleanExpression a = certificate.date.between(d1, d2);
BooleanExpression b = certificate.employee.forename.eq("name").
      or(certificate.employee.surname.eq("name"));

certificateRepository.findAll(a.and(b));

如果要查询Employees,请尝试以下针对QueryDSL版本4.1.3。

    QEmployee employee = QEmployee.employee;
    QCertificate certificate = QCertificate.certificate;

    BooleanExpression a = employee.forename.eq("name").or(employee.surname.eq("name"));

    BooleanExpression b = employee.certificates.contains(
        JPAExpressions.selectFrom(certificate).
          where(certificate.employee.eq(employee).
           and(certificate.date.between(d1, d2))));

    userRepository.findAll(a.and(b));

答案 1 :(得分:2)

由于这是使用MySQL标记发布的,我将回答您需要的查询(对于其他人),然后希望您可以从中找出QueryDSL代码:

SELECT * from Certificate 
    WHERE date > "2014-01-01 00:00:00" and date < "2015-01-01 00:00:00" AND 
    id IN (SELECT id from Employee 
           WHERE first_name LIKE '%Name%' 
                 || last_name LIKE '%LName%')

从带有输出的命令行:

mysql> SELECT * from Certificate 
    ->         WHERE date > "2014-01-01 00:00:00" and date < "2015-01-01 00:00:00" AND 
    ->         id IN (SELECT id from Employee 
    ->                WHERE first_name LIKE '%Name%' 
    ->                      || last_name LIKE '%LName%');
+----+--------------------+---------------------+--------+
| id | name               | date                | fk_emp |
+----+--------------------+---------------------+--------+
|  1 | FirstName LastName | 2014-02-01 00:00:00 |  11111 |
+----+--------------------+---------------------+--------+
1 row in set (0.00 sec)

抱歉,不熟悉QueryDSL,因此您需要修改代码以匹配该查询。

以下是我用来测试它的模式:

CREATE TABLE `Certificate` (
  `id` int(11) NOT NULL,
  `name` varchar(255) NOT NULL,
  `date` datetime NOT NULL,
  `fk_emp` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `Certificate` (`id`, `name`, `date`, `fk_emp`) VALUES
(1, 'FirstName LastName',   '2014-02-01 00:00:00',  11111);

CREATE TABLE `Employee` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `first_name` varchar(255) NOT NULL,
  `last_name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `Employee` (`id`, `first_name`, `last_name`) VALUES
(1, 'FirstName',    'LastName');