如何在 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

查看:36
本文介绍了如何在 Spring Boot 中实现通用 JPA 存储库 - 可以将其自动装配到任何实体/类类型的 spring 服务中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是扩展 spring PagingAndSortingRepository 的示例通用存储库实现,

Here is the sample Generic Repository implementation which extends the 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 );

}

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

实现类,

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.如果当我为客户和消息类型创建单独的存储库时,这会起作用.如果不创建多个存储库,我将无法实现这一点.

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. 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

如果有 100 个或更多实体类,那么我最终会创建 100 个存储库,这很糟糕.请让我知道是否有更好的方法来做到这一点.

If have 100 or more entity classes, then i end up creating 100's of repositories and which is bad. Please let me know if there is a better way to do this.

推荐答案

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

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...

 @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 的范围设置为原型,但这只是一种推测.如果我没有真正帮助我很抱歉,不要太讨厌我^^

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. I am sorry if i didn't really help, don't hate me too much ^^

这篇关于如何在 Spring Boot 中实现通用 JPA 存储库 - 可以将其自动装配到任何实体/类类型的 spring 服务中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆