我正在寻找Spring Data JPA。考虑下面的例子,我将得到所有的crud和查找器功能默认工作,如果我想自定义一个查找器,那么也可以在界面本身轻松完成。

@Transactional(readOnly = true)
public interface AccountRepository extends JpaRepository<Account, Long> {

  @Query("<JPQ statement here>")
  List<Account> findByCustomer(Customer customer);
}

我想知道如何添加一个完整的自定义方法及其实现以上AccountRepository?因为它是一个接口,我不能在那里实现方法。


当前回答

公认的答案是可行的,但有三个问题:

在将自定义实现命名为AccountRepositoryImpl时,它使用了一个未记录的Spring Data特性。文档明确指出它必须被称为AccountRepositoryCustomImpl,即自定义接口名加上Impl 不能使用构造函数注入,只能使用@Autowired,这被认为是不好的做法 在自定义实现中有一个循环依赖(这就是为什么不能使用构造函数注入)。

我找到了一个让它变得完美的方法,尽管不是没有使用另一个未记录的Spring Data特性:

public interface AccountRepository extends AccountRepositoryBasic,
                                           AccountRepositoryCustom 
{ 
}

public interface AccountRepositoryBasic extends JpaRepository<Account, Long>
{
    // standard Spring Data methods, like findByLogin
}

public interface AccountRepositoryCustom 
{
    public void customMethod();
}

public class AccountRepositoryCustomImpl implements AccountRepositoryCustom 
{
    private final AccountRepositoryBasic accountRepositoryBasic;

    // constructor-based injection
    public AccountRepositoryCustomImpl(
        AccountRepositoryBasic accountRepositoryBasic)
    {
        this.accountRepositoryBasic = accountRepositoryBasic;
    }

    public void customMethod() 
    {
        // we can call all basic Spring Data methods using
        // accountRepositoryBasic
    }
}

其他回答

你需要为你的自定义方法创建一个单独的接口:

public interface AccountRepository 
    extends JpaRepository<Account, Long>, AccountRepositoryCustom { ... }

public interface AccountRepositoryCustom {
    public void customMethod();
}

并为该接口提供一个实现类:

public class AccountRepositoryImpl implements AccountRepositoryCustom {

    @Autowired
    @Lazy
    AccountRepository accountRepository;  /* Optional - if you need it */

    public void customMethod() { ... }
}

参见:

4.6 Spring数据存储库的自定义实现 请注意,不同版本之间的命名方案发生了变化。详情见https://stackoverflow.com/a/52624752/66686。

除了axtavt的答案,不要忘记你可以在你的自定义实现中注入实体管理器,如果你需要它来构建你的查询:

public class AccountRepositoryImpl implements AccountRepositoryCustom {

    @PersistenceContext
    private EntityManager em;

    public void customMethod() { 
        ...
        em.createQuery(yourCriteria);
        ...
    }
}

考虑到您的代码片段,请注意,您只能将本机对象传递给findBy###方法,假设您想要加载属于某些客户的帐户列表,一个解决方案是这样做,

@Query("Select a from Account a where a."#nameoffield"=?1")
List<Account> findByCustomer(String "#nameoffield");

确保要查询的表的名称与Entity类相同。 关于进一步的实现,请看看这个

I扩展了SimpleJpaRepository:

public class ExtendedRepositoryImpl<T extends EntityBean> extends SimpleJpaRepository<T, Long>
    implements ExtendedRepository<T> {

    private final JpaEntityInformation<T, ?> entityInformation;

    private final EntityManager em;

    public ExtendedRepositoryImpl(final JpaEntityInformation<T, ?> entityInformation,
                                                      final EntityManager entityManager) {
       super(entityInformation, entityManager);
       this.entityInformation = entityInformation;
       this.em = entityManager;
    }
}

并将这个类添加到@EnableJpaRepositoryries repositoryBaseClass中。

公认的答案是可行的,但有三个问题:

在将自定义实现命名为AccountRepositoryImpl时,它使用了一个未记录的Spring Data特性。文档明确指出它必须被称为AccountRepositoryCustomImpl,即自定义接口名加上Impl 不能使用构造函数注入,只能使用@Autowired,这被认为是不好的做法 在自定义实现中有一个循环依赖(这就是为什么不能使用构造函数注入)。

我找到了一个让它变得完美的方法,尽管不是没有使用另一个未记录的Spring Data特性:

public interface AccountRepository extends AccountRepositoryBasic,
                                           AccountRepositoryCustom 
{ 
}

public interface AccountRepositoryBasic extends JpaRepository<Account, Long>
{
    // standard Spring Data methods, like findByLogin
}

public interface AccountRepositoryCustom 
{
    public void customMethod();
}

public class AccountRepositoryCustomImpl implements AccountRepositoryCustom 
{
    private final AccountRepositoryBasic accountRepositoryBasic;

    // constructor-based injection
    public AccountRepositoryCustomImpl(
        AccountRepositoryBasic accountRepositoryBasic)
    {
        this.accountRepositoryBasic = accountRepositoryBasic;
    }

    public void customMethod() 
    {
        // we can call all basic Spring Data methods using
        // accountRepositoryBasic
    }
}