在单个 table 继承类型中查找特定类型的元素
Find elements of specific type in single table inheritance type
设想以下实体层次结构:
@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;
}
我正在尝试创建一个 UI 来搜索 EntityUsingResource
并能够过滤具有特定 属性.
资源的元素
因此,在 GUI 的搜索字段中,您可以为 property4
输入一个值,它会过滤所有具有 [=17] 类型资源的 EntityUsingResource
=] whos 属性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 规范实用程序 class 一起使用,如下所示:
在哪里(
withResource2HavingProperty2Like(属性2)
)。和(
withResource4HavingProperty4Like(属性4)
);
然后我将其传递给 JpaRepository
,或多或少 return 结果传递给 gui。
这会在搜索 属性1 时创建以下 SQL:
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 ...;
问题是,这个查询产生了很多重复项。我尝试使用 distinct 来解决问题,但它引发了另一个问题。在 EntityUsingResource
实体中,我有一个类型为 json 的列,因此使用 distinct 将不起作用,因为数据库无法比较 json 值。
如何编写一个同时使用条件 api 过滤 Resource
类型的查询?
提前致谢:-)
如果您的目标是创建有效查询而不是使用条件 API,您可以使用 FluentJPA:
(property2
参数被自动捕获并作为参数传递)
public List<EntityUsingResource > findEntitiesUsingResource2(String property2) {
FluentQuery query = FluentJPA.SQL((EntityUsingResource entity) -> {
List<Long> resourceIds = subQuery((Resource res) -> {
SELECT(res.getEntityUsingResource().getId());
FROM(res);
WHERE(typeOf(res, Resource2.class) &&
((Resource2) res).getProperty2().getValue().matches("%" + property2 + "%"));
});
SELECT(entity);
FROM(entity);
WHERE(resourceIds.contains(entity.getId()));
});
return query.createQuery(em, EntityUsingResource.class).getResultList();
}
产生以下 SQL:
SELECT t0.*
FROM entity_using_resource t0
WHERE (t0.id IN (SELECT t1.entity_id
FROM resource t1
WHERE (t1.type = 'resource2' AND (t1.property2 LIKE CONCAT( CONCAT( '%' , ?1 ) , '%' ) ))) )
记录了 JPA 继承的支持 here。
设想以下实体层次结构:
@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;
}
我正在尝试创建一个 UI 来搜索 EntityUsingResource
并能够过滤具有特定 属性.
因此,在 GUI 的搜索字段中,您可以为 property4
输入一个值,它会过滤所有具有 [=17] 类型资源的 EntityUsingResource
=] whos 属性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 规范实用程序 class 一起使用,如下所示: 在哪里( withResource2HavingProperty2Like(属性2) )。和( withResource4HavingProperty4Like(属性4) );
然后我将其传递给 JpaRepository
,或多或少 return 结果传递给 gui。
这会在搜索 属性1 时创建以下 SQL:
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 ...;
问题是,这个查询产生了很多重复项。我尝试使用 distinct 来解决问题,但它引发了另一个问题。在 EntityUsingResource
实体中,我有一个类型为 json 的列,因此使用 distinct 将不起作用,因为数据库无法比较 json 值。
如何编写一个同时使用条件 api 过滤 Resource
类型的查询?
提前致谢:-)
如果您的目标是创建有效查询而不是使用条件 API,您可以使用 FluentJPA:
(property2
参数被自动捕获并作为参数传递)
public List<EntityUsingResource > findEntitiesUsingResource2(String property2) {
FluentQuery query = FluentJPA.SQL((EntityUsingResource entity) -> {
List<Long> resourceIds = subQuery((Resource res) -> {
SELECT(res.getEntityUsingResource().getId());
FROM(res);
WHERE(typeOf(res, Resource2.class) &&
((Resource2) res).getProperty2().getValue().matches("%" + property2 + "%"));
});
SELECT(entity);
FROM(entity);
WHERE(resourceIds.contains(entity.getId()));
});
return query.createQuery(em, EntityUsingResource.class).getResultList();
}
产生以下 SQL:
SELECT t0.*
FROM entity_using_resource t0
WHERE (t0.id IN (SELECT t1.entity_id
FROM resource t1
WHERE (t1.type = 'resource2' AND (t1.property2 LIKE CONCAT( CONCAT( '%' , ?1 ) , '%' ) ))) )
记录了 JPA 继承的支持 here。