简体   繁体   English

如何在 Spring Boot 中实现通用 JPA 存储库 - 它可以自动装配到任何实体/类类型的 spring 服务中

[英]How to implement Generic JPA Repository in Spring Boot - Which can be autowired into spring services for any entity/class type

Here is the sample Generic Repository implementation which extends the spring PagingAndSortingRepository,这是扩展 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 );

} }

Factory Bean class,工厂 Bean 类,

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;
    }
  }
}

Implementation 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();
   }

}

So when i try to Autowire GenericRepository into services for different types like Customer.java, Message.java etc it is throwing requires at least one bean type of interface GenericRepository.因此,当我尝试将 GenericRepository 自动装配到不同类型(如 Customer.java、Message.java 等)的服务中时,它抛出需要至少一种 bean 类型的接口 GenericRepository。 This works if when I create individual repositories for both customer and message type.如果当我为客户和消息类型创建单独的存储库时,这会起作用。 Without creating multiple repositories, i am not able to implement this.如果不创建多个存储库,我将无法实现这一点。

@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

If have 100 or more entity classes, then i end up creating 100's of repositories and which is bad.如果有 100 个或更多实体类,那么我最终会创建 100 个存储库,这很糟糕。 Please let me know if there is a better way to do this.请让我知道是否有更好的方法来做到这一点。

For what I've read it will be easier to tell the new interface methods what to do by @Query annotation and do not bother yourself with BeanFactory or impl...对于我读过的内容,通过@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 );
...
}

Using generics in Spring Data JPA repositories 在 Spring Data JPA 存储库中使用泛型

If that's not applicable for you and you are saying that your code works with one repository but fails when you add second my first thought is to try and set the scope of the bean to prototype but that is just a speculation.如果这对您不适用,并且您说您的代码适用于一个存储库但在您添加第二个时失败,我的第一个想法是尝试将 bean 的范围设置为原型,但这只是一种推测。 I am sorry if i didn't really help, don't hate me too much ^^如果我真的没有帮助,我很抱歉,不要太讨厌我^^

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM