首页 > 解决方案 > QueryDSL 与 Spring Boot Data JPA 的交集

问题描述

我在 Spring Boot、Spring Data JPA 项目中使用 QueryDSL。我有一个名为的表的以下架构test

| id | key  | value |
|----|------|-------|
| 1  | test | hello |
| 1  | test | world |
| 2  | test | hello |
| 2  | foo  | bar   |
| 3  | test | hello |
| 3  | test | world |

现在我想在 QueryDSL 中编写以下 SQL:

select id from test where key = 'test' and value = 'hello'
INTERSECT
select id from test where key = 'test' and value = 'world'

这会给我所有的 ID,其中键是“测试”,值是“你好”和“世界”。

我还没有找到在 QueryDSL 中声明这种 SQL 的任何方法。我能够编写两个 select 语句,但后来我被困在将它们与INTERSECT.

JPAQueryFactory queryFactory = new JPAQueryFactory(em); // em is an EntityManager

QTestEntity qTestEntity = QTestEntity.testEntity;

var q1 = queryFactory.query().from(qTestEntity).select(qTestEntity.id).where(qTestEntity.key("test").and(qTestEntity.value.eq("hello")));
var q2 = queryFactory.query().from(qTestEntity).select(qTestEntity.id).where(qTestEntity.key("test").and(qTestEntity.value.eq("world")));;

最后,我想检索与给定查询匹配的 id 列表。一般来说,相交的数量可能在 20 或 30 左右,具体取决于我要搜索的键/值对的数量。

有谁知道如何用 QueryDSL 做这样的事情?

编辑:

现在假设以下模式,有两个表:test和“用户”:

test:

| userId  | key  | value |
|---------|------|-------|
| 1       | test | hello |
| 1       | test | world |
| 2       | test | hello |
| 2       | foo  | bar   |
| 3       | test | hello |
| 3       | test | world |

user:

| id | name     |
|----|----------|
| 1  | John     |
| 2  | Anna     |
| 3  | Felicita |

对应的 java 类如下所示。TestEntity有一个由其所有属性组成的复合键。

@Entity
public class TestEntity {
    @Id
    @Column(name = "userId", nullable = false)
    private String pubmedId;

    @Id
    @Column(name = "value", nullable = false)
    private String value;

    @Id
    @Column(name = "key", nullable = false)
    private String key;
}

@Entity
class User {
  @Id 
  private int id;

  private String name;

  @ElementCollection
  private Set<TestEntity> keyValues;
}

如何将test表映射到类中的keyValues属性User

标签: javaspring-bootspring-data-jpaquerydsl

解决方案


您的 TestEntity 并不是真正的实体,因为它的 id 不是主键,而是用户表的外键。

如果它只能通过使用它的所有属性来识别,它就是一个@Embeddable,并且没有任何@Id 属性。

您可以将 Embeddables 的集合映射为另一个以 id 作为主键的实体的 @ElementCollection 部分。您的情况下的 id 列不是 Embeddable 的属性,它只是主表的外键,因此您将其映射为@JoinColumn:

@Embeddable
public class TestEmbeddable {

    @Column(name = "value", nullable = false)
    private String value;

    @Column(name = "key", nullable = false)
    private String key;
}

@Entity
class User {
  @Id 
  private int id;
  @ElementCollection
  @CollectionTable(
     name="test",
     joinColumns=@JoinColumn(name="id")
  )
  private Set<TestEmbeddable> keyValues;
}

在这种情况下,QueryDSL 变成了这样(不知道确切的 api):

user.keyValues.any().in(new TestEmbeddable("test", "hello"))
  .and(user.keyValues.keyValues.any().in(new TestEmbeddable("test", "world"))

推荐阅读