Spring数据JPA和NamedEntityGraphs
目前我正在努力只获取我需要的数据。findAll()方法需要根据调用它的位置来获取数据。 我不想为每个实体图编写不同的方法。 此外,我会避免调用EntityManager并自己形成(重复的)查询。 基本上,我想使用内置findAll方法,但我喜欢实体图。有机会吗Spring数据JPA和NamedEntityGraphs,jpa,fetch,spring-data-jpa,entitygraph,Jpa,Fetch,Spring Data Jpa,Entitygraph,目前我正在努力只获取我需要的数据。findAll()方法需要根据调用它的位置来获取数据。 我不想为每个实体图编写不同的方法。 此外,我会避免调用EntityManager并自己形成(重复的)查询。 基本上,我想使用内置findAll方法,但我喜欢实体图。有机会吗 @Entity @Table(name="complaints") @NamedEntityGraphs({ @NamedEntityGraph(name="allJoinsButMessages", attributeNode
@Entity
@Table(name="complaints")
@NamedEntityGraphs({
@NamedEntityGraph(name="allJoinsButMessages", attributeNodes = {
@NamedAttributeNode("customer"),
@NamedAttributeNode("handling_employee"),
@NamedAttributeNode("genre")
}),
@NamedEntityGraph(name="allJoins", attributeNodes = {
@NamedAttributeNode("customer"),
@NamedAttributeNode("handling_employee"),
@NamedAttributeNode("genre"),
@NamedAttributeNode("complaintMessages")
}),
@NamedEntityGraph(name="noJoins", attributeNodes = {
})
})
public class Complaint implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
private long id;
private Timestamp date;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "customer")
private User customer;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "handling_employee")
private User handling_employee;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="genre")
private Genre genre;
private boolean closed;
@OneToMany(mappedBy = "complaint", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<ComplaintMessage> complaintMessages = new ArrayList<ComplaintMessage>();
//getters and setters
}
@实体
@表(name=“投诉”)
@姓名识别图({
@NamedEntityGraph(name=“allJoinsButMessages”,attributeNodes={
@名称三方(“客户”),
@名称三方(“处理员工”),
@命名为“类型”
}),
@NamedEntityGraph(name=“allJoins”,attributeNodes={
@名称三方(“客户”),
@名称三方(“处理员工”),
@命名为“流派”,
@NamedAttributeNode(“投诉信息”)
}),
@NamedEntityGraph(name=“noJoins”,attributeNodes={
})
})
公共类实现了可序列化{
私有静态最终长serialVersionUID=1L;
@身份证
@生成值
私人长id;
私有时间戳日期;
@manytone(fetch=FetchType.LAZY)
@JoinColumn(name=“客户”)
私人用户客户;
@manytone(fetch=FetchType.LAZY)
@JoinColumn(name=“处理员工”)
私人用户处理(u)员工;;
@manytone(fetch=FetchType.LAZY)
@JoinColumn(name=“genre”)
私人体裁;
私有布尔闭;
@OneToMany(mappedBy=“投诉”,fetch=FetchType.LAZY,cascade=CascadeType.ALL)
private List complaintMessages=new ArrayList();
//接球手和接球手
}
还有我的JPA假设
@Repository
public interface ComplaintRepository extends JpaRepository<Complaint, Long>{
List<Complaint> findByClosed(boolean closed);
@EntityGraph(value = "allJoinsButMessages" , type=EntityGraphType.FETCH)
@Override
List<Complaint> findAll(Sort sort);
}
@存储库
公共接口投诉存储库扩展了JpaRepository{
列表findByClosed(布尔闭合);
@EntityGraph(value=“allJoinsButMessages”,type=EntityGraphType.FETCH)
@凌驾
列表findAll(排序);
}
我们遇到了一个类似的问题,并设计了几个可能的解决方案,但对于一个常见的问题,似乎没有一个优雅的解决方案
1) 前缀。数据jpa为一个方法名提供了几个前缀(find,get,…)。一种可能是对不同的命名图使用不同的前缀。这是最少的工作,但是对开发人员隐藏了方法的含义,并且有很大的可能导致错误实体加载的一些不明显的问题
@Repository
@Transactional
public interface UserRepository extends CrudRepository<User, Integer>, UserRepositoryCustom {
@EntityGraph(value = "User.membershipYearsAndPreferences", type = EntityGraphType.LOAD)
User findByUserID(int id);
@EntityGraph(value = "User.membershipYears", type = EntityGraphType.LOAD)
User readByUserId(int id);
}
@存储库
@交易的
公共接口UserRepository扩展了Crudepository、UserRepositoryCustom{
@EntityGraph(value=“User.membershipYearsAndPreferences”,type=EntityGraphType.LOAD)
用户findByUserID(int-id);
@EntityGraph(value=“User.membershipYears”,type=EntityGraphType.LOAD)
用户readByUserId(int-id);
}
2) 自定义存储库。另一种可能的解决方案是创建自定义查询方法并注入EntityManager。此解决方案为您的存储库提供了最干净的接口,因为您可以为您的方法命名一些有意义的名称,但要向代码中添加以提供解决方案会带来很大的复杂性,而且您需要手动获取实体管理器,而不是使用Spring magic
interface UserRepositoryCustom {
public User findUserWithMembershipYearsById(int id);
}
class UserRepositoryImpl implements UserRepositoryCustom {
@PersistenceContext
private EntityManager em;
@Override
public User findUserWithMembershipYearsById(int id) {
User result = null;
List<User> users = em.createQuery("SELECT u FROM users AS u WHERE u.id = :id", User.class)
.setParameter("id", id)
.setHint("javax.persistence.fetchgraph", em.getEntityGraph("User.membershipYears"))
.getResultList();
if(users.size() >= 0) {
result = users.get(0);
}
return result;
}
}
@Repository
@Transactional
public interface UserRepository extends CrudRepository<User, Integer>, UserRepositoryCustom {
@EntityGraph(value = "User.membershipYearsAndPreferences", type = EntityGraphType.LOAD)
User findByUserID(int id);
}
interface UserRepositoryCustom{
公共用户findUserWithMembershipYearsById(int-id);
}
类UserRepositoryImpl实现UserRepositoryCustom{
@持久上下文
私人实体管理者;
@凌驾
公共用户findUserWithMembershipYearsById(int id){
用户结果=null;
List users=em.createQuery(“从用户中选择u作为u,其中u.id=:id”,User.class)
.setParameter(“id”,id)
.setHint(“javax.persistence.fetchgraph”,em.getEntityGraph(“User.membershipYears”))
.getResultList();
如果(users.size()>=0){
结果=用户。获取(0);
}
返回结果;
}
}
@存储库
@交易的
公共接口UserRepository扩展了Crudepository、UserRepositoryCustom{
@EntityGraph(value=“User.membershipYearsAndPreferences”,type=EntityGraphType.LOAD)
用户findByUserID(int-id);
}
3) JPQL。本质上,这只是放弃命名实体图,使用JPQL为您处理连接。在我看来,这并不理想
@Repository
@Transactional
public interface UserRepository extends CrudRepository<User, Integer>, UserRepositoryCustom {
@EntityGraph(value = "User.membershipYearsAndPreferences", type = EntityGraphType.LOAD)
User findByUserID(int id);
@Query("SELECT u FROM users WHERE u.id=:id JOIN??????????????????????????")
User findUserWithTags(@Param("id") final int id);
}
@存储库
@交易的
公共接口UserRepository扩展了Crudepository、UserRepositoryCustom{
@EntityGraph(value=“User.membershipYearsAndPreferences”,type=EntityGraphType.LOAD)
用户findByUserID(int-id);
@查询(“从用户中选择u,其中u.id=:id JOIN?????”)
用户findUserWithTags(@Param(“id”)最终int-id);
}
我们选择了选项1,因为它是实现中最简单的,但这确实意味着当我们使用存储库时,我们必须查看获取方法,以确保我们使用的是具有正确实体图的方法。祝你好运
资料来源:
我没有足够的声誉来发布我所有的消息来源。抱歉:(将
@EntityGraph
与@Query
@Repository
public interface ComplaintRepository extends JpaRepository<Complaint, Long>{
@EntityGraph(value = "allJoinsButMessages" , type=EntityGraphType.FETCH)
@Query("SELECT c FROM Complaint ORDER BY ..")
@Override
List<Complaint> findAllJoinsButMessages();
@EntityGraph(value = "allJoins" , type=EntityGraphType.FETCH)
@Query("SELECT c FROM Complaint ORDER BY ..")
@Override
List<Complaint> findAllJoin();
...
@存储库
公共接口投诉存储库扩展了JpaRepository{
@EntityGraph(value=“allJoinsButMessages”,type=EntityGraphType.FETCH)
@查询(“根据……从投诉单中选择c”)
@凌驾
列出findAllJoinsButMessages();
@EntityGraph(value=“allJoins”,type=EntityGraphType.FETCH)
@查询(“根据……从投诉单中选择c”)
@凌驾
列出findAllJoin();
...
}我们也遇到了同样的问题,并构建了一个Spring数据JPA扩展来解决这个问题: 此扩展允许将命名或动态构建的EntityGraph作为任何存储库方法的参数传递 通过此扩展,您可以立即使用此方法:
List<Complaint> findAll(Sort sort, EntityGraph entityGraph);
List findAll(排序、EntityGraph、EntityGraph);
并且能够用Enti调用它
@EntityGraph(value = "fetch.Profile.Address.record", type = EntityGraphType.LOAD)
Employee getProfileAddressRecordById(long id);
@NamedEntityGraph(name="all.Customer.handling_employee.genre", attributeNodes = {
@NamedAttributeNode("customer"),
@NamedAttributeNode("handling_employee"),
@NamedAttributeNode("genre")
})
@EntityGraph(value = "all.Customer.handling_employee.genre" , type=EntityGraphType.FETCH)
findAllCustomerHandlingEmployeeGenre
interface UserRepository : PagingAndSortingRepository<UserModel, Long> {
@EntityGraph(attributePaths = arrayOf("address"))
fun findAnythingGoesHereById(id: Long): Optional<UserModel>
@EntityGraph(attributePaths = arrayOf("address"))
fun findAllAnythingGoesHereBy(pageable: Pageable): Page<UserModel>
}
@Repository
public interface ComplaintRepository extends JpaRepository<Complaint, Long>{
List<Complaint> findByClosed(boolean closed);
@EntityGraph(attributePaths = {"customer", "genre", "handling_employee" }, type=EntityGraphType.FETCH)
@Override
List<Complaint> findAll(Sort sort);
@EntityGraph(attributePaths = {"customer", "genre", "handling_employee", "messages" }, type=EntityGraphType.FETCH)
default List<Complaint> queryAll(Sort sort){
return findAll(sort);
}
}