Представьте себе следующую иерархию сущностей:
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type", columnDefinition = "varchar(60)")
abstract class Resource {
}
@Entity
@DiscriminatorValue("resource1")
class Resource1 extends Resource {
@Embedded
private Property property1;
}
@Entity
@DiscriminatorValue("resource2")
class Resource2 extends Resource {
@Embedded
private Property property2;
}
@Entity
@DiscriminatorValue("resource3")
class Resource3 extends Resource {
@Embedded
private Property property3;
}
@Entity
@DiscriminatorValue("resource4")
class Resource4 extends Resource {
@Embedded
private Property property4;
}
@Entity
class EntityUsingResource {
@OneToMany(...)
@JoinColumn(...)
private List<Resource> resources;
}
Я пытаюсь создать пользовательский интерфейс для поиска EntityUsingResource и иметь возможность фильтровать элементы, у которых есть ресурсы с определенным свойством.
Таким образом, в поле поиска в графическом интерфейсе вы можете ввести значение, скажем, property4, и оно отфильтрует все EntityUsingResource, у которых есть ресурс типа Resource4, чье свойство4 равно тому, которое вы ввели.
До сих пор мне удалось сделать это, используя этот критерий API с использованием спецификаций пружин:
public static Specification<EntityUsingResource>
withResource4HavingProperty4Like(String property4) {
Join<EntityUsingResource, Resource> join =
root.join(EntityUsingResource_.resources, JoinType.INNER);
Join<EntityUsingResource, Resource4> treatedJoin =
cb.treat(join, Resource4.class);
return cb.like(
treatedJoin.get(Resource4_.property4).get(Property_.value),
"%" + property4 + "%");
}
public static Specification<EntityUsingResource>
withResource2HavingProperty2Like(String property2) {
Join<EntityUsingResource, Resource> join =
root.join(EntityUsingResource_.resources, JoinType.INNER);
Join<EntityUsingResource, Resource2> treatedJoin =
cb.treat(join, Resource2.class);
return cb.like(
treatedJoin.get(Resource2_.property2).get(Property_.value),
"%" + property2 + "%");
}
Я использую эти спецификации с служебным классом Springs Specifications следующим образом: где (withResource2HavingProperty2Like (property2)).
Который я затем передаю в JpaRepository и более или менее возвращаю результат в графический интерфейс.
Это создает следующий SQL при поиске property1:
select
entity_using_resource0.id as entityId
from
entity_using_resource entity_using_resource0
inner join resource resourceas1_ on
entity_using_resource0.id=resourceas1_.entity_using_resource_id
inner join resource resourceas2_ on
entity_using_resource0.id=resourceas2_.entity_using_resource_id
inner join resource resourceas3_ on
entity_using_resource0.id=resourceas3_.entity_using_resource_id
inner join resource resourceas4_ on
entity_using_resource0.id=resourceas4_.entity_using_resource_id
where (resourceas4_.property1 like 'property1')
and (resourceas2_.property1 like '%property1%') limit ...;
Проблема в том, что этот запрос создает много дубликатов. Я попытался использовать Different, что решило бы проблему, но возникло другое. В объекте EntityUsingResource у меня есть столбец типа json, поэтому использование различных не будет работать, поскольку база данных не может сравнивать значения json.
Как написать запрос, который также фильтрует тип Resource, используя критерии API?
Заранее спасибо :-)