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

标签 java spring spring-data spring-data-jpa

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

我的问题是,在我写这篇文章之前,我为 findByLogin 使用了一个单独的 UserRepositoryCustom 接口(interface)的模式,然后是另一个类 UserRepositoryImpl在那个类中,我将有 @PersistenceContext 来获取当前的 EntityManager

当我没有类(class)时,如何获得 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);
    }
}

最佳答案

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

实际上,使用 reference documentation 中描述的自定义实现是正确的做法。这是供引用的简短版本(以防其他人也想知道):

/**
 * 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> { … }

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

您也可以让 UserRepository实现QueryDslPredicateExecutor并从存储库外部提交谓词,但这会让您最终得到需要使用 Querydsl 的客户端(这可能是不需要的),而且您不会得到 Optional包装类型 OOTB。

关于java - 我应该使用 Java 8 默认方法来手动实现 Spring Data 存储库方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26543612/

相关文章:

java - 如何在Java中使用 "or"?

java - Spring Hibernate 集成测试返回意外结果

spring - 存储库和服务层、QueryDSL 和 Spring Data

spring-boot - eclipse中的Spring data Querydsl不生成查询类型类

java - Tomcat 异常 : HTTP Status 500

Spring 数据 Elasticsearch 动态更改 indexName

java - 我无法从 java spring boot 中的属性访问数据

java - Hibernate javassist 代理和 `Object#equals`

java - 克隆可变成员

java - 为什么Spring Boot主应用总是触发PMD的HideUtilityClassConstructorCheck?