如何使用EntityManager#merge与使用EntityGraph创建的分离实体合并?

时间:2016-06-20 22:23:46

标签: hibernate jpa java-ee

此示例显示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)?

0 个答案:

没有答案