此示例显示User
对象。
@javax.persistence.Entity
public class User
{
@OneToMany(fetch=FetchType.LAZY, mappedBy="user")
public Set<UserRole> getUserRoles() { return this.userRoles; }
public void setUserRoles(Set<UserRole> userRoles) { this.userRoles = userRoles; }
}
@javax.persistence.Entity
public class UserRole
{
@ManyToOne(fetch=FetchType.LAZY, optional=false)
@JoinColumn(name = "roleid", referencedColumnName="id")
public Role getRole() { return this.role; }
public void setRole(Role role) { this.role = role; }
}
使用EntityGraph
检索角色,以避免抛出org.hibernate.LazyInitializationException
。
@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class SomeService
{
@PersistenceContext EntityManager em;
...
public void blah()
{
EntityGraph<User> userEntityGraph = em.createEntityGraph(User.class);
Subgraph<UserRole> userRolesSubgraph = userEntityGraph.addSubgraph("userRoles");
userRolesSubgraph.addAttributeNodes(UserRole_.role);
TypedQuery<User> query = em.createNamedQuery("User.findByEmail", User.class)
.setHint("javax.persistence.loadgraph", userEntityGraph)
.setParameter("email", "foo@bar.com");
User user = query.getSingleResult();
user.getUserRoles().iterator().next().getRole(); // Sweet! Gets the role.
}
}
User
对象将被分离并可供用户的登录会话使用。最终可能需要合并User
,例如,如果用户需要更改它的电子邮件。
@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class SomeOtherService
{
@PersistenceContext EntityManager em;
...
public User updateEmail(User user, String email)
{
user.setEmail(email);
User userNewVersion = em.merge(user);
userNewVersion.getUserRoles(); // Sweet! Gets the userRoles.
userNewVersion.getUserRoles().iterator().next().getRole(); // Throws org.hibernate.LazyInitializationException
return userNewVersion;
}
}
不幸的是,抛出org.hibernate.LazyInitializationException
,显然实体图配置不再存在。令人失望的是,JPA API没有提供在合并发生时重新引入实体图形配置的方法。有没有办法重新引入配置?也许我错过了什么。
另外,userRoles可用于新创建的userNewVersion
并且角色不可用并不奇怪吗?毕竟,userRoles和角色都配置为FetchType.LAZY。如果没有EntityGraph来添加属性节点User_.userRoles,访问userNewVersion
中的userRoles应该抛出org.hibernate.LazyInitializationException
- 但它不会。多奇怪。
如何在不丢失EntityGraph
配置的同时合并实体(如User),同时避免第二次数据库命中(例如通过执行后续的EntityManager#find
)?