den*_*iii 47 jpa fetch spring-data-jpa entitygraph
目前我正在努力只能获取我需要的数据.findAll()方法需要根据其被调用的位置获取数据.我不想最终为每个实体图编写不同的方法.此外,我会避免调用实体管理员并自己形成(重复)查询.基本上我想在findAll方法中使用构建,但是使用我喜欢的实体图.任何机会?
@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
}
Run Code Online (Sandbox Code Playgroud)
还有我的JPARepository
@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);
}
Run Code Online (Sandbox Code Playgroud)
小智 44
我们遇到了类似的问题,设计了几种潜在的解决方案,但似乎并没有成为一个优雅的解决方案似乎是一个常见的问题.
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);
}
Run Code Online (Sandbox Code Playgroud)
2)CustomRepository.另一种可能的解决方案是创建自定义查询方法并注入EntityManager.此解决方案为您提供了最清晰的存储库接口,因为您可以将方法命名为有意义的,但是为了提供解决方案而添加到代码中会产生大量复杂性,并且您手动抓取实体管理器而不是使用Spring魔法.
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);
}
Run Code Online (Sandbox Code Playgroud)
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);
}
Run Code Online (Sandbox Code Playgroud)
我们使用选项1,因为它是最简单的实现,但这确实意味着当我们使用我们的存储库时,我们必须查看fetch方法以确保我们使用具有正确实体图的那个.祝好运.
资料来源:
我没有足够的声誉来发布我的所有来源.对不起:(
Réd*_*oui 15
我们遇到了同样的问题并构建了一个Spring Data JPA扩展来解决它:
https://github.com/Cosium/spring-data-jpa-entity-graph
此扩展允许将命名或动态构建的EntityGraph作为任何存储库方法的参数传递.
使用此扩展程序,您可以立即使用此方法:
List<Complaint> findAll(Sort sort, EntityGraph entityGraph);
Run Code Online (Sandbox Code Playgroud)
并且能够使用在运行时选择的EntityGraph来调用它.
GKi*_*lin 11
使用@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();
...
Run Code Online (Sandbox Code Playgroud)
}
正如我从本文@EntityGraph中发现的,在派生查询上使用注释是可能的。文章中有这样的例子:
@Repository
public interface ArticleRepository extends JpaRepository<Article,Long> {
@EntityGraph(attributePaths = "topics")
Article findOneWithTopicsById(Long id);
}
Run Code Online (Sandbox Code Playgroud)
但我不认为“with”有什么特别之处,而且实际上可以有find和之间的任何内容By。我尝试了这些并且它们起作用了(这段代码是 Kotlin,但想法是相同的):
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>
}
Run Code Online (Sandbox Code Playgroud)
该文章提到了一个警告,即您无法创建类似于findAll在没有By条件的情况下查询所有记录的方法并用作findAllWithTopicsByIdNotNull()示例。我发现仅By在名称末尾包含其本身就足够了:findAllWithTopicsBy()。更简洁,但读起来可能更混乱。使用以不带任何条件结尾的方法名称By可能会在 Spring 的未来版本中面临中断的危险,因为它似乎不是派生查询名称的预期用途。
看起来在 Spring 中解析派生查询名称的代码位于github 上。如果您对派生查询存储库方法名称的可能性感到好奇,可以查看那里。
这些是派生查询的 spring 文档。
这是用 spring-data-commons-2.2.3.RELEASE 测试的
| 归档时间: |
|
| 查看次数: |
33512 次 |
| 最近记录: |