如何为 @MappedSuperclass 实现 Spring Data 存储库

2022-01-18 00:00:00 java jpa spring-data generics

我有一个 JPA @MappedSuperClass 和一个扩展它的 @Entity:

I've got a JPA @MappedSuperClass and an @Entity extending it:

@MappedSuperclass
public class BaseClass {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column
    private Boolean active;

    //getters & setters

}

@Entity
public class Worker extends BaseClass{

    @Column
    private String name;

    //getters & setters

}

基类的active 字段是子实体的标志.只有活动的应该加载到应用程序中.然后我写了一个通用的 Spring Data Proxy 接口:

The active field of the base class is a flag for the children entities. Only the active ones should be loaded in the application. Then I've written a generic Spring Data Proxy interface:

public interface Dao<T extends BaseClass, E extends Serializable> extends
        CrudRepository<T, E> {

    Iterable<T> findByActive(Boolean active);

}

而这个应该是Worker数据访问的接口,适当地扩展了上一个:

And this one is the interface that should be for Worker data access, properly extending the previous one:

@Transactional
public interface WorkerDao extends Dao<Worker, Long>{}

好吧,现在在我的逻辑层中,我实现了一个抽象类,它将包装我的实体上 CRUD 操作的通用代码.我将为他们每个人提供服务,但我只想从 abstract 继承.我想为每个服务连接特定的存储库,并使用 abstract 方法将其提供给超类.这就是我的超类的实现方式:

Well, now in my logic layer I've implemented an abstract class which will wrap the common code for CRUD operations over my entities. I'll have a service for each of them, but I want just to inherit from the abstract one. I want to wire the specific repository for each of the services and provide it to the superclass using an abstract method. That's how my superclass is implemented:

public abstract class GenericService<E extends BaseClass>{

    public abstract Dao<E, Long> getDao();

    //Here I've got some common operations for managing 
    //all my application classes, including Worker

}

问题在于 getDao() 方法使用了 E 类参数,该参数只能保证是 BaseClass 的子类,并且不是 javax.persistence.Entity.当我尝试从我的自定义服务实现访问 DAO 时,我收到此错误:

The problem is that the getDao() method uses the E class parameter, which is guaranteed only to be a child of BaseClass and not a javax.persistence.Entity. When I try to access the DAO from my custom service implementation I get this error:

原因:java.lang.IllegalArgumentException:无法为方法 public abstract java.lang.Iterable com.mycompany.model.daos.interfaces.Dao.findByActive(java.lang.Boolean) 创建查询元模型!在 org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:93)

Caused by: java.lang.IllegalArgumentException: Could not create query metamodel for method public abstract java.lang.Iterable com.mycompany.model.daos.interfaces.Dao.findByActive(java.lang.Boolean)! at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:93)

原因:java.lang.IllegalArgumentException:不是实体:com.mycompany.model.BaseClass 类在 org.hibernate.jpa.internal.metamodel.MetamodelImpl.entity(MetamodelImpl.java:203)

Caused by: java.lang.IllegalArgumentException: Not an entity: class com.mycompany.model.BaseClass at org.hibernate.jpa.internal.metamodel.MetamodelImpl.entity(MetamodelImpl.java:203)

这是有道理的,因为 E 被定义为 BaseClass 的子级.编译器也允许我这样写:

Which makes sense, because E is defined as a child of BaseClass. The compiler allows me to write this too:

public abstract class GenericService<E extends BaseClass && Entity>

但是,我在子服务中收到一个错误,提示 Worker 类与 E 的签名不兼容.有人知道怎么解决吗?

However I get an error in the child Service that says Worker class is not compatible with the signature for E. Does anybody know how to solve this?

推荐答案

只是将抽象的Repository注释为@NoRepositoryBean:

@NoRepositoryBean
public interface Dao<T extends BaseClass, E extends Serializable> extends
        CrudRepository<T, E> {

    Iterable<T> findByActive(Boolean active);

}

这种方式 Spring 依赖于底层存储库实现来执行 findByActive 方法.

This way Spring relies on the underlying repository implementation to execute the findByActive method.

关于注解类型限制问题,无法声明注解限制类型.请参阅下面的参考答案.

Regarding to the annotation type restriction issue, it's not possible to declare an annotation restricted type. See the referenced answers below.

另请参阅:

  • 通用 Spring Data JPA 存储库按类类型加载数据的实现
  • 注解:限制对带有注解的类的引用

相关文章