Пересечение QueryDSL с данными Spring Boot JPA - PullRequest
0 голосов
/ 04 мая 2020

Я использую QueryDSL в проекте Spring Boot, Spring Data JPA. У меня есть следующая схема для таблицы с именем test:

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

Теперь я хочу написать следующее SQL в QueryDSL:

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

Что даст мне все идентификаторы где ключ - это «тест», а значения - «привет» и «мир».

Я пока не нашел способа объявить этот тип SQL в QueryDSL. Я могу написать два оператора 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")));;

В конце я хочу получить список идентификаторов, которые соответствуют данному запросу. В общем, количество пересечений может быть около 20 или 30, в зависимости от количества пар ключ / значение, которые я хочу найти.

Кто-нибудь знает способ, как сделать что-то подобное с QueryDSL?

РЕДАКТИРОВАТЬ:

Теперь предположим следующую схему с двумя таблицами: test и 'user':

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?

1 Ответ

0 голосов
/ 04 мая 2020

Ваш TestEntity на самом деле не является сущностью, поскольку его идентификатор не является первичным ключом, это внешний ключ для пользовательской таблицы.

Если его можно определить только по всем его свойствам, это @Embeddable, и не имеет свойств @Id.

Вы можете отобразить коллекцию Embeddables как часть @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"))
...