我应该对手动实现的Spring Data存储库方法使用Java 8默认方法吗?

2022-09-02 10:20:51

在使用新的Spring Data Evans版本时,能够使用java 8附带的一些好东西真是太好了。其中之一是接口中的默认实现。下面的存储库使用 QueryDSL 使查询类型安全。

我的问题是,在我写这篇文章之前,我使用了一个单独的接口的模式,然后是另一个类,在那个类中,我将得到电流。UserRepositoryCustomfindByLoginUserRepositoryImpl@PersistenceContextEntityManager

当我没有课程时,我如何获得?这有可能吗?EntityManager

@Repository
public interface UserRepository extends JpaRepository<User, UUID> {

    final QUser qUser = QUser.user;

    // How do I get the entityManager since this is a interface, i cannot have any variables?
    //@PersistenceContext
    //EntityManager entityManager;

    public default Optional<User> findByLogin(String login) {
        JPAQuery query = new JPAQuery(entityManager);
        User user = query
                .from(qUser)
                .where(
                        qUser.deleter.isNull(),
                        qUser.locked.isFalse(),
                        qUser.login.equalsIgnoreCase(login)
                )
                .singleResult(qUser);

        return Optional.ofNullable(user);
    }
}

答案 1

默认方法应仅用于将调用委派给其他存储库方法。根据定义,默认方法无法访问实例的任何状态(因为接口没有)。它们只能委托给其他接口方法或调用其他类的静态方法。

实际上,使用参考文档中所述的自定义实现是正确的方法。以下是供参考的简短版本(以防其他人也想知道):

/**
 * Interface for methods you want to implement manually.
 */
interface UserRepositoryCustom {
  Optional<User> findByLogin(String login);
}

/**
 * Implementation of exactly these methods.
 */
class UserRepositoryImpl extends QueryDslRepositorySupport implements UserRepositoryCustom {

  private static final QUser USER = QUser.user;

  @Override
  public Optional<User> findByLogin(String login) {

    return Optional.ofNullable(
      from(USER).
      where(
        USER.deleter.isNull(),
        USER.locked.isFalse(), 
        USER.login.equalsIgnoreCase(login)).
      singleResult(USER));
  }
}

/**
 * The main repository interface extending the custom one so that the manually
 * implemented methods get "pulled" into the API.
 */
public interface UserRepository extends UserRepositoryCustom, 
  CrudRepository<User, Long> { … }

请注意,命名约定在这里很重要(但可以根据需要进行自定义)。通过扩展,您可以访问该方法,这样您就不必与自己交互。QueryDslRepositorySupportfrom(…)EntityManager

或者,您可以让实现并从存储库外部输入谓词,但这会使您最终遇到需要使用Querydsl的客户端(这可能是不需要的),并且您不会获得包装器类型OOTB。UserRepositoryQueryDslPredicateExecutorOptional


答案 2

您不会在界面中获取 ,尽管您可以通过执行查找来解决此问题。EntityManager

但是你为什么要这样做呢?Spring Data JPA已经支持返回类型,因此您无需实现它。Spring Data将为您完成。Optional

public interface UserRepository extends JpaRepository<User, UUID> {

    Optional<User> findByLoginIgnoreCase(String login) {
}

上面的代码应该是您所需要的。您甚至可以指定一个查询,如果需要它。@Query

在此处找到示例。


推荐