【问题标题】:Find elements of specific type in single table inheritance type在单表继承类型中查找特定类型的元素
【发布时间】:2019-11-08 10:33:55
【问题描述】:

想象以下实体层次结构:

@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 来搜索 EntityUsingResources 并能够过滤具有特定属性的资源的元素。

因此,在 GUI 的搜索字段中,您可以为 property4 输入一个值,它会过滤所有具有 Resource4 类型资源的 EntityUsingResources,其属性 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) )。和( withResource4HavingProperty4Like(property4) );

然后我将其传递给 JpaRepository 并或多或少地将结果返回给 gui。

这会在搜索 property1 时创建以下 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 的类型?

提前致谢:-)

【问题讨论】:

    标签: hibernate jpa spring-data-jpa criteria criteria-api


    【解决方案1】:

    如果您的目标是创建有效的查询而不是使用标准 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

    【讨论】:

    • 我将它标记为解决方案,虽然我还没有尝试过。我会在尝试后立即提供反馈。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 2021-08-22
    • 1970-01-01
    • 2021-01-23
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    • 2019-07-26
    • 2020-06-22
    相关资源
    最近更新 更多