【问题标题】:hibernate java curiosity - after saving the object, both the object to save and the saved one have id sethibernate java好奇心 - 保存对象后,要保存的对象和保存的对象都设置了id
【发布时间】:2016-09-22 13:22:13
【问题描述】:

我有以下简单的代码:

@Test
public void saveExpense() {
    // Create dummy Expense object i.e. { "description": "Short Description", "date": etc } 
    Expense expenseToSave = ExpenseHelper.createExpense("Short Description", new Date(), user);

    Expense savedExpense = expenseService.save(expenseToSave);

    // What is strange, is that here, both expenseToSave and savedExpense have id set to 1 for example; after save the expense should have an id; 

    Expense expected = ExpenseHelper.createExpense("Short Description", new Date(), user);
    // Check if expected object is equal to the saved one
    Assert.assertTrue(expected.equals(expenseService.findByDescription("Short Description")));
}

通常我希望expenseToSave 没有id 而savedExpense 有id,但在保存后两者都有id。为什么?

这使得另一个变量变得必要并使测试复杂化。

谢谢。

【问题讨论】:

  • 查看是否expenseToSave == savedExpense

标签: java hibernate unit-testing


【解决方案1】:

这就是 Hibernate Session.save() 方法的指定方式。来自documentation

持久化给定的瞬态实例,首先分配一个生成的 标识符。 (或者使用标识符属性的当前值,如果 使用分配的生成器。)此操作级联到关联 如果关联使用 cascade="save-update" 映射,则实例。

ID 是 Hibernate 如何区分持久对象和瞬态对象以及识别特定对象的机制。因此,ID 是在持久化步骤的早期设置的,例如对象树中的循环引用在持久化时通过 ID 解析。

返回对象与原始对象的区别在于返回对象附加到 Hibernate 会话。例如,通过主动级联,包含的实体(例如在一对多集合中)现在在返回的对象中也是持久实例。

【讨论】:

    【解决方案2】:

    请注意

    void EntityManager#persist(java.lang.Object entity)
    

    (http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#persist%28java.lang.Object%29)

    通过更改传入的对象来保留给定的对象,并且 not 返回一个持久副本 - 我怀疑您的 ExpenseHelper 会另外返回原始对象,以便您通过 return 接收相同的对象你已经通过传入它。

    这遵循了一种常见的反模式,即 DAO 的一种统一行为类似于

    public T create(T entity) {
        this.entityManager.persist(entity);
    
        return entity;
    }
    

    获得一种与保存东西的同步性

    public T save(T entity) {
        return this.entityManager.merge(entity);
    }
    

    在哪里

    <T> T EntityManager#merge(T entity)
    

    确实合并并将合并后的实体传递给您。

    【讨论】:

    • 那么是通过引用传递的,那么呢?酷。
    • 您可以随时更改通过参数获取的对象内容,不同之处在于此处的 JPA 规范明确定义实体不能是不可变对象,因为它们将通过持久化进行更改。
    【解决方案3】:

    它可以依赖于 Expense 实体的 Hibernate 映射,或者 ExpenseHelper 类的实现。

    另外,看看 Expense.equals() 的实现。

    【讨论】:

    • 嗨,谢谢你的回答;似乎可以重新分区。 Waht ExpenseHelper 所做的是创建一个新的 Expense 实例并返回它,所以我想是关于 Hibernate;我很好奇他们是怎么做到的。
    【解决方案4】:

    基于此声明: Expense savedExpense = expenseService.save(expenseToSave); savedExpense 对象的值将取决于您在 save 方法中所做的事情。通常保存方法不返回对象。您已经拥有对刚刚保存的对象 (expenseToSave) 可用的引用。而且您试图断言您的expected 对象equals 是已保存的对象,这很好。所以我不确定在expenseService.save(expenseToSave)中返回一个对象的目的是什么

    另外,请注意,对象expenseToSave 的 id 将根据您的配置在保存时由您的 ORM(我假设为 Hibernate)填充。无需在 save 方法中返回此对象或其他对象。

    【讨论】:

      猜你喜欢
      • 2015-03-01
      • 2015-12-11
      • 1970-01-01
      • 1970-01-01
      • 2020-09-03
      • 1970-01-01
      • 2015-07-04
      • 1970-01-01
      • 2014-08-04
      相关资源
      最近更新 更多