Представьте себе следующую иерархию сущностей:
@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?
Заранее спасибо :-)