使用延迟初始化属性分离JPA对象

mik*_*ail 5 orm hibernate jpa transactions lazy-loading

有两个JPA实体:具有一对多关系的用户和订单.

/**
 * User DTO
 */
@Entity
@Table(name="user")
public class User implements Serializable {
    private static final long serialVersionUID = 8372128484215085291L;

    private Long id;
    private Set<Order> orders;

    public User() {}

    @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="sequenceUser")
    public Long getId() {
        return this.id;
    }
    private void setId(Long id) {
        this.id = id;
    }

    @OneToMany(mappedBy="user", cascade=CascadeType.PERSIST, fetch=FetchType.LAZY)
    @LazyCollection(LazyCollectionOption.EXTRA)
    public Set<Order> getOrders() {
        return orders;
    }
    public void setOrders(Set<Order> orders) {
        this.orders = orders;
    }
 }


/**
 * Order DTO
 */
@Entity
@Table(name="order")
public class Order implements Serializable {
    private static final long serialVersionUID = 84504362507297200L;

    private Long id;
    private User user;

    public Order() {
    }

    @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="sequenceOrder")
    public Long getId() {
        return this.id;
    }
    private void setId(Long id) {
        this.id = id;
    }

    @ManyToOne
    @JoinColumn(name="user_id")
    public User getUser(){
        return user;
    }
    public void setUser(User user){
        this.user = user;
    }
}
Run Code Online (Sandbox Code Playgroud)

我在服务层类中使用这些实体,其中每个方法都在事务中运行.一切都很好,除非服务层类的方法必须返回这些实体.

@Transactional(readOnly=true)
public Set<Order> getOrders() {
    Set<Order> orders = user.getOrders();

    return orders;
}
Run Code Online (Sandbox Code Playgroud)

This method returns data well. But when I try access to received collection elements I catch exception: "org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: package.User.orders, no session or session was closed".

So, it was excepted. I thought that detaching result will solve my problem, but trick like this

@Transactional(readOnly=true)
public Set<Order> getOrders() {
    Set<Order> orders = user.getOrders();

    for(Order order: orders)
        entityManager.detach(order);
    return orders;
}
Run Code Online (Sandbox Code Playgroud)

didn't change anything :(

It doesn't matter for me will info about users attend in set of orders or not. I just want to work with this set and not going to modify it.

Can anybody help me? :)

Pas*_*ent 7

该方法很好地返回数据.但是,当我尝试访问收到集合元素我赶上例外:"org.hibernate.LazyInitializationException:无法初始化懒洋洋角色的集合:package.User.orders,没有会话或会话已关闭".

错误是自我解释:您正在尝试加载(延迟)加载的集合,但由于User实例已分离,因此不再存在活动会话.

所以,它被排除在外.我认为分离结果将解决我的问题,但这样的伎俩

这不会改变任何事情.该EntityManager#detach(Object)方法不加载任何内容,它从持久化上下文中删除传递的实体,使其分离.

对我来说无关紧要是关于用户是否参加订单的信息.我只是想使用这个集合,而不是去修改它.

您需要使关联EAGER(以便在检索用户时加载Orders)或在检索服务中的用户时使用FETCH JOIN:

SELECT u
FROM User u LEFT JOIN FETCH u.orders
WHERE u.id = :id
Run Code Online (Sandbox Code Playgroud)

我是否正确理解hibernate没有强制加载当前对象的所有延迟关联的标准机制

Hibernate有一个Hibernate.initialize方法,但这显然不是标准的JPA(更喜欢为可移植代码提取连接).

我没办法让hibernate忽略当前对象的懒惰关联(将它们设置为null)

什么?无视你的意思是什么?你为什么要那样做呢?