保存时禁用 ManyToOne 关系 JPA 中的级联
Disable Cascade in ManyToOne relationship JPA when saving
我在数据库中保存实体时遇到问题。
我有类似的东西(非常简单):
@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代码。这是为数据库中的旧实体执行的修复,保存时没有更新此字段。
已编辑 2
这就是我使用 EntityManager 保存实体 Employee 的方式(如果是新对象,则坚持,否则更新它)
if (entity.getId() == null) {
entityManager.persist(entity);
return entity;
}
return entityManager.merge(entity);
加载 Employee
实体时,您可能还会加载 Building
实体(取决于您的 JPA-provider 和版本,fetchtype EAGER 或 LAZY 是默认值),并且在加载 Building
实体时,您还将加载与其连接的所有 Employees
。
这意味着加载一个 Employee
-实体 will/might 加载所有连接到相同 Building
的 Employee
,因此 运行 @PostLoad
-所有这些的方法。当这种情况发生在事务内部时,我会假设 @PostLoad
方法所做的更改在事务提交时会保留。
只是扩展了 Tobb 的回答:
发生这种情况是因为您正在使用合并调用加载 Employee 。该实体与建筑有 1:1 关系,默认为急切获取,强制建筑也被加载。
Building 也有一个 1:M 给 Employees,你用 fetch = FetchType.EAGER 标记了它,强制所有员工也被加载。
如果您不想加载所有员工,从而强制 JPA 调用他们的 postLoad 方法,您需要阻止加载这些关系中的一个或多个。选项:
- 将一个或多个标记为 fetch = FetchType.LAZY
- 这对于集合来说是微不足道的,但是 1:1 映射可能需要额外的支持。例如 EclipseLink 需要编织
- 从实体中删除一个或多个映射。
- 删除更改实体的 postLoad 逻辑。这似乎不是操纵实体的最佳位置,因为即使事务中可能没有其他更改,对它们的任何访问都会强制更新。您可能想出一种不同的策略,例如一次性批量更新遗留数据,而不是长期影响您的应用程序的策略。如果必须,可以改用@PreUpdate
如果您选择使用延迟提取,这仍然可以根据需要通过提取连接、查询提示和/或 fetch/load 组在逐个查询的基础上被覆盖。
我在数据库中保存实体时遇到问题。
我有类似的东西(非常简单):
@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代码。这是为数据库中的旧实体执行的修复,保存时没有更新此字段。
已编辑 2
这就是我使用 EntityManager 保存实体 Employee 的方式(如果是新对象,则坚持,否则更新它)
if (entity.getId() == null) {
entityManager.persist(entity);
return entity;
}
return entityManager.merge(entity);
加载 Employee
实体时,您可能还会加载 Building
实体(取决于您的 JPA-provider 和版本,fetchtype EAGER 或 LAZY 是默认值),并且在加载 Building
实体时,您还将加载与其连接的所有 Employees
。
这意味着加载一个 Employee
-实体 will/might 加载所有连接到相同 Building
的 Employee
,因此 运行 @PostLoad
-所有这些的方法。当这种情况发生在事务内部时,我会假设 @PostLoad
方法所做的更改在事务提交时会保留。
只是扩展了 Tobb 的回答: 发生这种情况是因为您正在使用合并调用加载 Employee 。该实体与建筑有 1:1 关系,默认为急切获取,强制建筑也被加载。
Building 也有一个 1:M 给 Employees,你用 fetch = FetchType.EAGER 标记了它,强制所有员工也被加载。
如果您不想加载所有员工,从而强制 JPA 调用他们的 postLoad 方法,您需要阻止加载这些关系中的一个或多个。选项:
- 将一个或多个标记为 fetch = FetchType.LAZY
- 这对于集合来说是微不足道的,但是 1:1 映射可能需要额外的支持。例如 EclipseLink 需要编织
- 从实体中删除一个或多个映射。
- 删除更改实体的 postLoad 逻辑。这似乎不是操纵实体的最佳位置,因为即使事务中可能没有其他更改,对它们的任何访问都会强制更新。您可能想出一种不同的策略,例如一次性批量更新遗留数据,而不是长期影响您的应用程序的策略。如果必须,可以改用@PreUpdate
如果您选择使用延迟提取,这仍然可以根据需要通过提取连接、查询提示和/或 fetch/load 组在逐个查询的基础上被覆盖。