【问题标题】:Hibernate clone entity without lazy fields没有惰性字段的休眠克隆实体
【发布时间】:2019-10-24 22:36:31
【问题描述】:

我有两个实体:

@Entity
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;

    @Column(name = "age")
    private int age;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "person_id")
    private Person person;

@Entity
@Table(name = "persons")
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;

    @Column(name = "number")
    private String number;

这个人很懒惰。我加载一个用户并将其分离。

    @Transactional
    @Override
    public void run(String... args) {
        User user = userService.getOne(1L);

        userService.detach(user);

        System.out.println(user.getName());
        System.out.println(user.getAge());
        Person person = user.getPerson();
        System.out.println(person.getName());
        System.out.println(person.getNumber());
    }

但是当我调用user.getPerson() - 它不会抛出异常。我预计会出现异常,因为我分离实体并尝试调用 LAZY 字段,但它仍然有效。

我想创建一个没有人的用户克隆并保存为新实体。

User user = userService.getOne(1L);
userService.detach(user);
user.setId(null)//autogenerate id

但是当我保存用户时,也会克隆人。我可以设置null:

User user = userService.getOne(1L);
userService.detach(user);
user.setId(null);
user.setPerson(null);

但是人很懒,看起来像个黑客。那么detach方法有什么意义...

编辑:

非常有趣的事情 - 如果我在使用断点调试时启动示例应用程序 - 一切正常,但如果我取消选择所有断点,我会在控制台中出现异常:

Caused by: org.hibernate.LazyInitializationException: could not initialize proxy [com.example.detachexample.User#1] - no Session

【问题讨论】:

  • 当您调用 detach 时,该对象将从会话中分离(如事务)并且不会保存到数据库中,除非您再次附加它......但它的所有属性保持不变
  • 在您的用例中,您需要在分离“用户”后刷新会话。准备好“克隆”对象后,您将需要一个打开的会话

标签: java hibernate spring-data-jpa entitymanager


【解决方案1】:

似乎在detach这一点上Person实际上已经被加载了。

根据FetchType 文档,这是可能的:

LAZY 策略是对持久性提供程序运行时的提示, 首次访问数据时应延迟获取数据。这 允许实现急切地获取 LAZY 的数据 已指定策略提示。

因此,请查看 Hibernate 调试日志,很可能会在某个地方加入到 Person 及其字段的选择。

【讨论】:

  • 是的,我看到了休眠日志。首先 - 加载没有此人的唯一用户。之后,我调用 detach 方法。在那之后,我打电话给user.getPerson()。 hibernate 进行新查询(标准延迟加载)。但是我不明白如果用户已经分离了怎么办。
【解决方案2】:

如果我理解的话,您是在对克隆调用 detach 吗?嗯,克隆不是普通的用户对象,而是扩展用户对象的代理。

您需要先使用unproxy 获取原始加载的实体。

User olduser = userService.getOne(1L);
User user = org.hibernate.Hibernate.unproxy(olduser);
if (olduser == user) userService.detach(user);
user.setId(null)//autogenerate id
user.getPerson().setId(null); // so you will generate this as well
user.getPerson().setUser(user); // so that it will point to the correct new entity

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-07
    • 1970-01-01
    • 2015-12-15
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    相关资源
    最近更新 更多