【问题标题】:Spring-data-jpa - When does .save() not return the same entity?Spring-data-jpa - .save() 什么时候不返回相同的实体?
【发布时间】:2018-07-31 23:56:47
【问题描述】:

在这段代码中,我保存了主对象和该对象的外键。 我打印出应该是完全相同的对象的“实体”和“事物”。但他们不是。为什么?

thingList.forEach(entity -> {
            System.out.println(entity);

            // Save if the foreign key exists and isn't already saved in the database
            if(entity.ForeignKey() != null && ForeignKeyRepository.findOne(entity.ForeignKey().getId()) == null)
            {
                ForeignKeyRepository.save(entity.getForeignKey());
            }
            Thing thing = thingRepository.save(entity);
            System.out.println(thing);
        });

【问题讨论】:

  • 因为它们不一样。如果它是一个新对象,您的对象将被替换为休眠托管实体,它是您实际实体的代理实例。
  • @M.Deinum 实际上是相反的。如果已经存在一个与返回的 id 相同的托管实体。

标签: java database spring spring-data spring-data-jpa


【解决方案1】:

如果实体不是新实体,并且在EntityManager 的会话中已经有一个表示数据库行的不同实例,您将获得该实例,修改为与作为参数传递的实例匹配,作为返回值。

您可以通过检查实现和相关的 JPA 文档来确认这一点。

save方法在SimpleJpaRepository中实现

public <S extends T> S save(S entity) {

    if (entityInformation.isNew(entity)) {
        em.persist(entity);
        return entity;
    } else {
        return em.merge(entity);
    }
}

emEntityManager。来自 merge 方法文档:

返回:状态合并到的托管实例

JPA specification 3.2.7.1 节更明确一点:

• 如果 X 是分离实体,则将 X 的状态复制到具有相同身份的预先存在的托管实体实例 X' 或创建 X 的新托管副本 X'。

• 如果 X 是一个新的实体实例,则创建一个新的托管实体实例 X',并将 X 的状态复制到新的托管实体实例 X'。

• 如果 X 是已移除的实体实例,则合并操作将抛出 IllegalArgumentException(或事务提交将失败)。

• 如果 X 是托管实体,则合并操作将忽略它,但是,如果这些关系已使用级联元素值 cascade=MERGE 或 cascade= 注释,则合并操作将级联到由 X 的关系引用的实体所有注释。

【讨论】:

  • 我会接受您的回答,因为它提供了有关正在发生的事情的良好信息。但是我在其他地方出了点问题,JPA 已经按照你的解释做了所有事情——所以它返回了相同的实例。原因是我以错误的方式阅读输出,所以我解释错了。
【解决方案2】:

这是他们在保存方法的文档中提到的例外

S save(S entity) : 保存给定的实体。使用返回的实例进行进一步的操作,因为保存操作可能完全改变了实体实例。

【讨论】:

    猜你喜欢
    • 2020-03-26
    • 2014-10-20
    • 1970-01-01
    • 2012-01-27
    • 2018-05-20
    • 1970-01-01
    • 2017-09-17
    • 1970-01-01
    相关资源
    最近更新 更多