我已将应用程序分为三层:控制器,服务,存储库。这非常有用,因为我可以在任何层上进行更改而不会影响其他层。
当前,我正在尝试优化一些查询,在某些地方实体图和生成的查询不足以满足我的需求。通过编写本机SQL并映射结果集,我自己使用了现有的@Entity
,相信可以更快地生成数据。
鉴于我有一些界面:
public interface UserRepository extends CrudRepository<User, Long> {}
如何扩展UserRepository
使其既使用CrudRepository
方法(例如save()
,findById()
)又使用我自己的本机查询方法。
我正在使用Spring Boot在Java 8中的每个租户数据库环境中使用hibernate作为持久性提供程序。我考虑过以下解决方案,但还不满意:
我在Spring Data Docs中找不到任何描述如何执行此操作的信息,但是我敢肯定,我已经在网上某处看到了这样的解决方案。
为清楚起见,我希望这样做:
public interface UserRepository extends CrudRepository<User, Long> {};
public class UserRepositoryImpl extends UserRepository {
public User doComplexQuery() {
List<Result> rows = query.("select * from ... ");
User user = new User(rows.get(0));
return user;
}
};
public class UserService {
@Autowired private UserRepository userRepository;
public User getUser() {
return userRepository.doComplexQuery();
}
public User saveUser(User user) {
return userRepository.save(user);
}
}
答案 0 :(得分:1)
对我来说,最好和最简单的选择是将您描述的所有选项结合在一起,用projections(如果我正确理解您的话)。
我使用Lombok
创建简单的实体@Data
@Builder
@NoArgConstructor
@AllArgsConstructor
@Entity
public class Model implements Serializable {
//...
private String name;
@OneToMany
private List<Subject> subjects;
}
@Data
@Builder
@NoArgConstructor
@AllArgsConstructor
@Entity
public class Subject implements Serializable {
//...
}
然后定义必要的投影,例如:
public interface ModelSubjects {
List<Subject> getSubjects();
}
public interface SomeProjection {
//...
}
然后根据需要扩展我的仓库:
public interface ModelRepo extends JpaRepository<Model, Long> {
@Query("select distinct m from Model m join fetch m.subjects where ...")
List<Model> getWithJPQLQuery(...);
@Query("select s as subjects from Model m join m.subjects s where ...")
List<ModelSubjects> getSubjectsWithJPQLQuery(...);
@Query(value = "some complex SQL query...", nativeQuery = true)
List<SomeProjection> getWithSQLQuery(...);
@EntityGraph(attributePaths = "subjects")
List<Model> findByName(String name);
}
已更新
复杂的示例(请参见答案下方的注释):
@Entity
public class Forest {
//...
private String name;
@OneToMany
private List<Tree> trees;
}
@Entity
public class Tree {
//...
@OneToMany
private List<Branch> branches;
}
@Entity
public class Branch {
//...
}
public interface BranchNumberByForest {
String getForestName();
Long getBranchNumber();
}
本地查询
public interface ForestRepo extends JpaRepository<Forest, Long> {
@Query(value = "" +
"select " +
" f.name as forestName, " +
" count(b.*) as branchNumber " +
"from " +
" forests f " +
" left join trees t on t.forest_id = f.id " +
" left join branches b on b.tree_id = t.id " +
"group by " +
" f.name", nativeQuery = true)
List<BranchNumberByForest> getBranchNumbers();
}
与JPQL相同
public interface ForestRepo extends JpaRepository<Forest, Long> {
@Query("" +
"select " +
" f.name as forestName, " +
" count(b) as branchNumber " +
"from " +
" Forest f " +
" left join f.trees t " +
" left join t.branches b " +
"group by " +
" f.name")
List<BranchNumberByForest> getBranchNumbers();
}
答案 1 :(得分:1)
我认为您正在寻找的是custom method implementations。
请注意,您可以将EntityManager
或任何其他Spring Bean注入到实现类中。
因此解决方案看起来类似于:
public interface UserRepository extends CrudRepository<User, Long>, CustomUserRepository {};
public interface CustomUserRepository {
User doComplexQuery();
};
public class CustomUserRepositoryImpl implements UserRepository {
@Autowired
EntityManager em;
public User doComplexQuery() {
List<Result> rows = em.createNativeQuery("select * from ... ");
User user = new User(rows.get(0));
return user;
}
};