如何在Spring Boot中实现Generic JPA Repository-它可以自动连接到任何实体/类类型的Spr



这是一个示例Generic Repository实现,它扩展了spring PagingAndSortingRepository,

@NoRepositoryBean
public interface GenericRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {
  public List<T> findByNamedQuery( String name );
  public List<T> findByNamedQueryAndParams( String name, Map<String, Object> params );
  public T findOneByNamedQuery( String name );
  public T findOneByNamedQueryAndParams( String name, Map<String, Object> params );

}

工厂豆类,

public class GenericRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable> extends
    JpaRepositoryFactoryBean<R, T, I> {
   @SuppressWarnings( "rawtypes" )
   protected RepositoryFactorySupport createRepositoryFactory( EntityManager em )
   {
    return new MyRepositoryFactory(em);
   }
   private static class MyRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory {
    private final EntityManager em;
    public MyRepositoryFactory( EntityManager em )
    {
        super(em);
        this.em = em;
    }
    @SuppressWarnings( "unchecked" )
    protected Object getTargetRepository( RepositoryMetadata metadata )
    {
        return new GenericRepositoryImpl<T, I>((Class<T>) metadata.getDomainType(), em);
    }
    protected Class<?> getRepositoryBaseClass( RepositoryMetadata metadata )
    {
        return GenericRepositoryImpl.class;
    }
  }
}

实现类,

public final class GenericRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements
    GenericRepository<T, ID> {
  private final EntityManager em;
  private final Class<T> domainClass;
  public GenericRepositoryImpl( Class<T> domainClass, EntityManager entityManager )
  {
      super(domainClass, entityManager);
      this.em = entityManager;
      this.domainClass = domainClass;
  }
  @Override
  public List<T> findByNamedQuery( final String name )
  {
      validate(name);
      return this.em.createNamedQuery(name, domainClass).getResultList();
  }
  @Override
  public T findOneByNamedQuery( String name )
  {
      validate(name);
      return this.em.createNamedQuery(name, domainClass).getSingleResult();
  }
  @Override
  public List<T> findByNamedQueryAndParams( String name, Map<String, Object> params )
   {
      validate(name, params);
      final TypedQuery<T> query = this.em.createQuery(name, domainClass);
      setParams(query, params);
      return query.getResultList();
   }
}

因此,当我尝试将GenericRepository自动连接到不同类型的服务(如Customer.java、Message.java等)时,它所抛出的至少需要一个bean类型的接口GenericRepository。如果我同时为客户和消息类型创建单独的存储库,这种方法就会起作用。如果不创建多个存储库,我就无法实现这一点。

@Service
@Transactional( noRollbackFor = Exception.class )
public class CustomerService {
@Autowired
private GenericRepository<Customer, Serializable> cr; works fine with just one entity type
@Autowired
private GenericRepository<Message, Serializable> cr; throws exception

如果有100个或更多的实体类,那么我最终会创建100个存储库,这很糟糕。如果有更好的方法,请告诉我。

就我所读到的内容而言,通过@Query注释告诉新的接口方法该做什么将更容易,并且不必为BeanFactory或impl而烦恼。。。

 @Repository
 public interface GenericRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
@Query(value = "SELECT c FROM customers c WHERE c.name = :name")
public List<T> findByNamedQuery( String name );
...
}

在Spring Data JPA存储库中使用泛型

如果这不适用于您,并且您说您的代码使用一个存储库,但在添加第二个存储库时失败,我的第一个想法是尝试将bean的范围设置为原型,但这只是一种猜测。如果我没有真正帮助我,我很抱歉,不要太恨我^^

最新更新