保存

时间:2016-01-20 10:22:19

标签: java jpa eclipselink cascade many-to-one

我在数据库中保存实体时遇到问题。

我喜欢(非常简化):

@Entity
public class Building {

    @OneToMany(mappedBy = "building", fetch = FetchType.EAGER)
    private List<Employee> employees;

}  

@Entity
public class Employee {

    @NotNull
    @ManyToOne
    @JoinFetch(INNER)
    @JoinColumn
    private Building building;

    @PostLoad
    private void onLoad(){
          if (this.plannedOrder == null) {
            //For old entities in this DB, update plannedOrder if null
            if (this.order < FIRST.getCode()) {
                this.plannedOrder = FIRST;
            } else if (this.order >= FIRST.getCode() && this.order < SECOND.getCode()) {
                this.plannedOrder = SECOND;
            } else if (this.order >= DEFAULT.getCode() && this.order < SEC_LAST.getCode()) {
                this.plannedOrder = DEFAULT;
            } else if (this.order >= SEC_LAST.getCode() && this.order < LAST.getCode()) {
                this.plannedOrder = SEC_LAST;
            } else if (this.order >= LAST.getCode()) {
                this.plannedOrder = LAST;
            } else {
                this.plannedOrder = DEFAULT;
            }
    }

}

问题是当我保存一个Employee实体时。在Building实体中,您将修改所有员工,因为@PostLoad注释,因此JPA将尝试更新这些实体。但是,我只想更新Employee实体。

有没有办法在不改变模型中的关系的情况下这样做?可以成为删除onLoad函数的解决方案吗?

谢谢!

编辑:

添加了PostLoad的PostLoad代码。这是对DB中的旧实体执行的修复,没有在保存时更新此字段。

已编辑2

这就是我用我的EntityManager保存我的实体Employee的方式(如果是新的Object,则保留,否则更新它)

    if (entity.getId() == null) {
        entityManager.persist(entity);
        return entity;
    }
    return entityManager.merge(entity);        

2 个答案:

答案 0 :(得分:1)

只是扩展了Tobb的回答: 发生这种情况是因为您正在使用合并调用加载Employee。此实体与构建的关系为1:1,默认为Eagerly fetched,强制构建也被加载。

构建那么员工也有1:M,并且你用fetch = FetchType.EAGER标记了它,强制所有员工也被加载。

如果您不希望加载所有员工,从而强制JPA调用其postLoad方法,则需要阻止加载这些关系中的一个或多个。选项:

  1. 将一个或多个标记为fetch = FetchType.LAZY
    • 这对于集合来说是微不足道的,但是使用1:1映射可能需要额外的支持。例如,EclipseLink需要编织
  2. 从实体中删除一个或多个映射。
  3. 删除更改实体的postLoad逻辑。这似乎不是操纵实体的最佳位置,因为对它们的任何访问都会强制更新,即使事务中可能没有其他更改。您可能会提出不同的策略,例如遗留数据的一次性批量更新,而不是长期影响应用程序的内容。如果必须,可以使用@PreUpdate
  4. 如果您选择使用延迟提取,则仍可以根据需要通过提取连接,查询提示和/或提取/加载组按查询覆盖此方法。

答案 1 :(得分:0)

加载Employee - 实体时,您可能还会加载Building - 实体(取决于您的JPA提供程序和版本,无论是fetchtype EAGER还是LAZY是默认值),以及加载时Building - 实体,您还将加载与其相关联的所有Employees

这意味着加载一个Employee - 实体将/可能加载连接到同一Employee的所有Building,从而为所有这些运行@PostLoad - 方法。当在事务中发生这种情况时,我会假设在事务提交时,@PostLoad - 方法所做的更改会保留。