首页 > 解决方案 > 抽象类中的休眠 NamedQuery

问题描述

我有 20 个继承自AbstractEntity的类,它们都需要具有相同的 NamedQueries,举个简单的例子:

@NamedQuery(name = Bootle.FIND_BY_ID, query = //
        "SELECT entity FROM " + Bootle.ENTITY_NAME + " entity " + 
        "LEFT OUTER JOIN FETCH entity.value val " + 
        "..." +
        "WHERE entity.id = :pIds AND entity.relationable = :pBoolean")

我希望我可以将这些查询移动到 AbstractEntity,但是我无法确定休眠的 EntityName。理想的解决方案是以某种方式拥有它:

@NamedQuery(name = BaseDAO.FIND_BY_ID, query = //
            "SELECT entity FROM " + AbstractEntity.ENTITY_NAME + " entity " + 
            "LEFT OUTER JOIN FETCH entity.value val " + 
            "..." +
            "WHERE entity.id = :pIds AND entity.relationable = :pBoolean")

但是上面的例子不起作用。当我查询此方法时,Hibernate 本身可以给出正确的实体名称吗?

当前查询调用示例:

getEntityManager().createNamedQuery(BaseDAO.FIND_BY_ID)
                .setParameter("pId", 201L)
                .setParameter("pBoolean", false);

标签: javapostgresqlhibernate

解决方案


从文档。https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query.spel-expressions

为避免在 @Query 注释的查询字符串中声明实际实体名称,您可以使用#{#entityName}变量。

entityName 可以使用@Entity 注解进行自定义。SpEL 表达式不支持 orm.xml 中的自定义。当然,您可以直接在查询声明中使用 User,但这也需要您更改查询。对 #entityName 的引用将 User 类的潜在未来重新映射到不同的实体名称(例如,通过使用 @Entity(name = "MyUser")。

查询字符串中#{#entityName} 表达式的另一个用例是,如果您想为具体域类型定义具有专用存储库接口的通用存储库接口。为了不在具体接口上重复自定义查询方法的定义,您可以在通用存储库接口中的@Query 注解的查询字符串中使用实体名称表达式。

例子

@MappedSuperclass
public abstract class AbstractMappedType {
  …
  String attribute
}

@Entity
public class ConcreteType extends AbstractMappedType { … }

@NoRepositoryBean
public interface MappedTypeRepository<T extends AbstractMappedType>
  extends Repository<T, Long> {

  @Query("select t from #{#entityName} t where t.attribute = ?1")
  List<T> findAllByAttribute(String attribute);
}

public interface ConcreteRepository
  extends MappedTypeRepository<ConcreteType> { … }

推荐阅读