Custom JPA Data Repository的基本服务

时间:2018-02-18 07:09:34

标签: java generics spring-data-jpa

  

我已将自定义JPA存储库实现为:

class Customer
{
    public:

    // One for other
    Customer (char[MAX] name,int age);
    // copy constructor
    Customer (const Customer& );
    // To print out the customer
    void displayCust ();
    // Some other useful functions

    private:

    char *name;
    int age;
    char sex;
};


enum CustomerType {Senior, Lady, Other};

class CustomerQueue
{
    public:
    CustomerQueue ();
    ~CustomerQueue ();
    CustomerQueue (const CustomerQueue&);
    void enqueue (Customer );
    Customer dequeue ();
     // four isEmpty functions
    bool isGenEmpty () const;
     // four printQueue functions
    void displayQueue();
     // some other useful functions

    int getNo ();

    private:
    struct Node;
    typedef Node* NodePtr;
    struct Node
    {
         CustomerType ct;
         Customer cust;
         NodePtr next;
    };

    NodePtr head,tail;


};
  

现在,我想创建一个通用的数据服务:

public class BaseEntity{...}

public class DerivedEntity extends BaseEntity{...}

@NoRepositoryBean
public interface BaseRepository<T extends BaseEntity> extends JpaRepository<T, ID>{
//some common method
}

@Repository
public interface DerivedRepository extends BaseRepository<DerivedEntity>{
}

现在,代码中的某处我想使用save方法:

public class CommonService{

private BaseRepository<? extends BaseEntity> baseRepository;


  //wants to use common method by passing derivedRepository
  public CommonService(BaseRepository<? extends BaseEntity>  derivedRepository) {
    this.baseRepository=derivedRepository;
  }

}
  

我收到编译时错误:

     

无法解析保存

如何解决此问题和设计? 什么是使用通用数据存储库设计公共数据服务的最佳方式?

1 个答案:

答案 0 :(得分:0)

PECS rule:Producer Extends,Consumer Super。这是一个首字母缩略词,可以帮助我们记住何时应该使用super以及何时应该使用extends。在这种情况下,save()方法是消费者。它接收一个对象,但不返回它。所以它应该是super - 它编译:

private BaseRepository<? super BaseEntity> baseRepository;
// ...
public void foo(BaseEntity entity ) {
    baseRepository.save(entity);
}

但是,JpaRepository也有生产者方法,例如findAll()。如果您的CommonService也使用了这个,那么此private BaseRepository<? super BaseEntity> baseRepository;将毫无用处。

还有一种解决方法:您可以在服务级别指定实体类型,并在方法级别更灵活:

public static class CommonService {

    private BaseRepository<BaseEntity> baseRepository;

    public CommonService(BaseRepository<BaseEntity> derivedRepository) {
        this.baseRepository = derivedRepository;
    }

    // here you can accept any subtype you want
    public <T extends BaseEntity> void foo(T entity) {
        baseRepository.save(entity);
    }

    // you can be flexible here
    public List<? super BaseEntity> bar() {
        return baseRepository.findAll();
    }

}

不幸的是,这些extends以及super?标志中的大多数都会使此代码的用户感到困难。我建议尽量保持简单。如果这还不够,那么您可以使用泛型,直到找到满足您需求的解决方案 。这将是最简单的解决方案:

    // accepts subclasses of BaseEntity
    public void foo(BaseEntity entity) {
        baseRepository.save(entity);
    }

    // reutrns a List<BaseEntity>. The _items_ of the list might be subclasses of BaseEntity.
    public List<BaseEntity> bar() {
        return baseRepository.findAll();
    }

实施说明:

以下行未定义ID类型。这类似于IntegerLong - BaseEntity的字段。

public static interface BaseRepository<T extends BaseEntity> extends JpaRepository<T, ID>