【发布时间】:2023-03-25 14:56:01
【问题描述】:
我们遇到了一个问题,我们必须维护一个日期字段 - 并且最好保留它的值 - 其中日期字段取决于其他实体的状态。用 JPA2 + Hibernate + Spring 解决这个问题的正确方法是什么?
基本上,我们有三个实体,我们称它们为Parent、Child 和Conf。 dependentDate 由依赖于其他实体状态的复杂业务规则计算得出。具体来说,应该是 Parent#date 减去 Conf#delay 跳过所有周末或节假日(持久数据)。
问题是每当Parent#date 发生变化时,所有孩子的dependentDates 都应该重新计算。每当 Child 对象的 conf 更改时,也会发生这种情况。目前有一种基于Child对象关系计算新日期的服务方法(我们称之为calculateDate())。
我们面临着应该在哪里计算字段值的问题。我想出了三个可能的解决方案。其中哪一个(或者可能是其他)是更新依赖于其他实体状态的实体字段的首选方式?
- JPA
EntityListener- JPA2 规范不鼓励这样做,因为 EntityListener 不应访问其他实体
- 字段总是正确的
- 更新的 Spring AOP 方面
- 逻辑隐藏在其他类中,不容易看到
- 切入点无法捕获所有持久/更新事件的风险
- 每个开发者都为自己
- 总是,在更新 Parent 或 Child 类的实例时,开发人员必须记住调用服务的
calculateDate()方法 - 这应该在 dao 层还是服务层?
- 开发者忘记添加调用,导致错误状态的风险
- 总是,在更新 Parent 或 Child 类的实例时,开发人员必须记住调用服务的
下面的例子展示了省略注解配置的实体关系。
实体
public class Parent {
LocalDate date;
Set<Child> children; // one-to-many
}
public class Conf {
int delay;
}
public class Child {
LocalDate dependentDate;
Conf conf; // many-to-one
Parent parent; // many-to-one
}
【问题讨论】:
-
这不应该是一个答案,而是一个“选项 4”:您可以在数据库中添加一个触发器,在更新其他表时更新日期字段。这当然只有在以下情况下才有效:a)您的 dbms 支持触发器,b)您愿意将业务逻辑移出您的主软件,并且 c)您的实体是“无状态的”(就像在 spring mvc 设置中一样)。
-
@realsim 您所说的“无状态”实体是什么意思?在我看来,实体只是一个状态(免责声明,我知道 JPA 但不知道 Spring)
-
我的意思是在休眠会话提交后,它不会被再次使用(因为触发器的实体不在会话认为的状态)。如果会话将被重用,它将以 StaleObjectStateException 结束。但是,如果会话因请求/响应完成而关闭,并且将在下一个请求时创建另一个会话,则该方法会很好。 - 我不喜欢自己将业务逻辑从代码中移出,但有时触发器是必要的......
标签: java spring hibernate jpa persistence