更新依赖于其他实体状态的@Entity字段的正确方法

时间:2012-11-23 09:00:25

标签: java spring hibernate jpa persistence

我们遇到了一个问题,我们必须维护一个日期字段 - 并且最好保持其值 - 日期字段依赖于其他实体的状态。用JPA2 + Hibernate + Spring解决这个问题的正确方法是什么?

基本上,我们有三个实体,我们称之为ParentChildConfdependentDate由依赖于其他实体状态的复杂业务规则计算。具体来说,它应该是Parent#date减去Conf#delay跳过周末或假期的所有日子(持久数据)。

问题是每当Parent#date发生变化时,都应重新计算所有孩子的dependentDate。每当Child对象的conf发生更改时,也会发生这种情况。目前,有一种服务方法可以根据Child对象的关系计算新日期(让我们称之为calculateDate())。

我们面临的问题是应该计算字段的值。我提出了三种可能的解决方案。哪些 - 或者可能是其他 - 是更新依赖于其他实体状态的实体字段的首选方式?

  1. JPA EntityListener
    • 在JPA2规范中不鼓励这样做,因为EntityListeners不应该访问其他实体
    • 该字段永远是正确的
  2. 更新的Spring AOP方面
    • 逻辑隐藏在其他类中并且不容易看到
    • 切入点无法捕获所有持久性/更新事件的风险
  3. 每个开发者都为自己
    • 总是,在更新Parent或Child类的实例时,开发人员必须记得调用服务的calculateDate()方法
    • 应该是dao还是服务层?
    • 开发者忘记添加呼叫的风险,导致错误状态
  4. 以下示例显示了省略注释配置的实体关系。

    实体

    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
    }
    

2 个答案:

答案 0 :(得分:2)

依赖于多个实体状态的复杂业务规则属于服务层。在应用程序中应该没有太多地方改变父母的日期和孩子的conf,所以你不应该有很多地方必须进行新的日期计算。

如果您真的有这么多地方,那么您可以明确指出必须通过将ChildDateUpdater实例(ChildDateUpdater作为接口)传递给父日期的设置者和子项的setter来重新计算日期CONF。这将明显表示每次更改这两个字段时都必须执行某些操作:

在家长中:

public void setDate(Date date, ChildDateUpdater childDateUpdater) {
    this.date = date;
    for (Child child : children) {
        childDateUpdater.updateChildDate(child);
    }
}

在孩子:

public void setConf(Conf conf, ChildDateUpdater childDateUpdater) {
    this.conf = conf;
    childDateUpdater.updateChildDate(this);
}

答案 1 :(得分:0)

在DAO中封装您的数据访问。如果要保存Parent,请检查其值是否有任何更改,如果是,请相应地更新子项。

realsim的触发选项也是可行的(基本上它是在不同级别实现的相同的想法)但是你会丢失可移植性(并且还会出现已经加载的子实例不存在的问题更新)。