将 Querydsl 与 Spring 数据一起使用时的最佳实践
Best practise when using Querydsl with Spring Data
使用 Spring Data nad Querydsl 我们可以只声明存储库接口并跳过实现 class。一些具有特定名称或使用@Query 注释的方法,仅此而已。
但有时我想使用 JPAQuery 并自己定义方法的主体,比方说
@Repository
public class MyRepositoryImpl implements MyRepository {
@PersistenceContext
private EntityManager em;
@Override
public List<Tuple> someMethod(String arg) {
JPAQuery query = new JPAQuery(em);
...
}
但这样我就必须实现其他 MyRepository 接口方法,这会破坏所有 Spring Data 的优势!
我可以看到两个选项:
- 为每个存储库声明另一个接口,然后正常实现它(接口数量加倍)
- 将 EntityManager 注入 @Service class 并在那里实现我的自定义方法
我更喜欢选项 #2,但据我所知,在 @Service class 中我们应该只调用存储库方法,因此它也不是一个完美的解决方案。
那么程序员是如何应对的呢?
您不应该实现实际的 Spring 数据存储库,而是必须声明另一个自定义接口,您可以在其中放置自定义方法。
假设您有一个 MyRepository
,定义为
@Repository
public interface MyRepository extends JpaRepository<Tuple, Long> {}
现在您想添加自定义 findTuplesByMyArg()
,为此您需要创建自定义存储库界面
public interface MyRepositoryCustom {
List<Tuple> findTuplesByMyArg(String myArg);
}
之后是自定义接口的实现
public class MyRepositoryImpl implements MyRepositoryCustom {
@PersistenceContext
private EntityManager em;
@Override
public List<Tuple> findTuplesByMyArg(String myArg) {
JPAQuery query = new JPAQuery(em);
...
}
}
而且我们需要更改 MyRepository
声明,因此它扩展了自定义存储库,因此
@Repository
public interface MyRepository extends JpaRepository<Tuple, Long>, MyRepositoryCustom {}
并且您可以通过注入 MyRepository
轻松访问您的 findTuplesByMyArg()
,例如
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
public List<Tuple> retrieveTuples(String myArg) {
return myRepository.findTuplesByMyArg(myArg);
}
}
注意名称在这里很重要(在 repo 实现中默认配置需要 Impl
后缀)。
您可以找到所有需要的信息here
我建议对上面的答案稍作修改,该答案尝试使用 JPAQueryFactory。最好利用提供的工厂 class.
public class MyRepositoryImpl implements MyRepositoryCustom {
@Autowired
private JPAQueryFactory factory;
@Override
public List<Tuple> findTuplesByMyArg(String myArg) {
JPAQuery query = factory.query();
...
}}
@Configuration
public class Config {
@Autowired
private EntityManager em;
@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(em);
}
}
使用 Spring Data nad Querydsl 我们可以只声明存储库接口并跳过实现 class。一些具有特定名称或使用@Query 注释的方法,仅此而已。
但有时我想使用 JPAQuery 并自己定义方法的主体,比方说
@Repository
public class MyRepositoryImpl implements MyRepository {
@PersistenceContext
private EntityManager em;
@Override
public List<Tuple> someMethod(String arg) {
JPAQuery query = new JPAQuery(em);
...
}
但这样我就必须实现其他 MyRepository 接口方法,这会破坏所有 Spring Data 的优势!
我可以看到两个选项:
- 为每个存储库声明另一个接口,然后正常实现它(接口数量加倍)
- 将 EntityManager 注入 @Service class 并在那里实现我的自定义方法
我更喜欢选项 #2,但据我所知,在 @Service class 中我们应该只调用存储库方法,因此它也不是一个完美的解决方案。
那么程序员是如何应对的呢?
您不应该实现实际的 Spring 数据存储库,而是必须声明另一个自定义接口,您可以在其中放置自定义方法。
假设您有一个 MyRepository
,定义为
@Repository
public interface MyRepository extends JpaRepository<Tuple, Long> {}
现在您想添加自定义 findTuplesByMyArg()
,为此您需要创建自定义存储库界面
public interface MyRepositoryCustom {
List<Tuple> findTuplesByMyArg(String myArg);
}
之后是自定义接口的实现
public class MyRepositoryImpl implements MyRepositoryCustom {
@PersistenceContext
private EntityManager em;
@Override
public List<Tuple> findTuplesByMyArg(String myArg) {
JPAQuery query = new JPAQuery(em);
...
}
}
而且我们需要更改 MyRepository
声明,因此它扩展了自定义存储库,因此
@Repository
public interface MyRepository extends JpaRepository<Tuple, Long>, MyRepositoryCustom {}
并且您可以通过注入 MyRepository
轻松访问您的 findTuplesByMyArg()
,例如
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
public List<Tuple> retrieveTuples(String myArg) {
return myRepository.findTuplesByMyArg(myArg);
}
}
注意名称在这里很重要(在 repo 实现中默认配置需要 Impl
后缀)。
您可以找到所有需要的信息here
我建议对上面的答案稍作修改,该答案尝试使用 JPAQueryFactory。最好利用提供的工厂 class.
public class MyRepositoryImpl implements MyRepositoryCustom {
@Autowired
private JPAQueryFactory factory;
@Override
public List<Tuple> findTuplesByMyArg(String myArg) {
JPAQuery query = factory.query();
...
}}
@Configuration
public class Config {
@Autowired
private EntityManager em;
@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(em);
}
}