1

我有一个有六个属性和一个更改日期的类。

@Entity
@Table(name = "product")
public class Product {

   private Long id;

   private String title; // if changed, update lastChanged

   private String subtitle;

   private Text summary; // if changed, update lastChanged

   private Text description; // if changed, update lastChanged

   private Text otherText;

   private List<Text> reviews; // if changed, update lastChanged

   private Date lastChanged;

   // Getters and setters

}

-

@Entity
@Table(name = "text")
public class Text {

   private Long id;

   private String content;

   private int typeCode;

   // Getters and setters

}

(这显然是我们实际领域模型的大规模简化版本,但它说明了基本问题)

要求是:如果“title”、“summary”、“description”或“reviews”发生变化,请将“lastChanged”设置为当前日期。
背景:这些字段与外部 API 相关。我的客户想知道,自 X 日以来,哪些产品对其 API 相关字段进行了更改。

我试图通过实现 Hibernate Interceptors 和 Hibernate Event Listeners 来满足要求。他们都没有像我希望的那样工作。例如,当我更改“摘要”时,Hibernate 只会告诉我:“文本”表中的“内容”字段已更改。

这个信息不是很有用,因为我仍然不知道'summary'、'description'或'otherText'是否被改变了。因此我不知道是否需要更新“lastChanged”。

我的其他想法:

  • 获取已更改的 Text 对象的 id 并尝试通过 SQL 查找与其连接的产品。这可能会起作用,但它是一个非常丑陋的解决方案,并且它会与我们的域模型变得非常复杂。

  • 在变量设置器中实现更新逻辑。这样做有两个问题:Hibernate 在从数据库加载对象时调用 setter(这当然不会导致更新时间戳)并且它不能解决上述问题。如果“内容”的设置器被调用,那会怎样?我不知道,产品的哪个属性被改变了。

这个问题有什么优雅的解决方案吗?

4

1 回答 1

0

以通用方式解决更改通知问题并非易事,尤其是当您需要一种不会盲目发送通知的有状态机制时——例如,源自基础架构某些部分的更改不会触发通知。

您的问题的细节也可能使问题简化或复杂化。例如,同一个Text对象可以被一个对象的多个字段引用Product吗?同样,它是否可以在不同的Product对象之间共享?如果其中任何一个是可能的,那么当共享对象发生更改时,您必须确定正确的行动方案是什么——例如,您是否通知所有相关方?

构建通知基础设施的基本设计模式之一是观察者模式。您可以使用这种方法让所有对象观察它们引用的所有Product对象的变化。Text

如果这种方法对于您的目的来说太复杂或太慢,您可能需要重新考虑您的架构。例如,使Text类不可变是否有意义?或者,如果每个Text对象仅被一个其他对象引用,是否可以添加一个额外的字段Text以指向其父对象以及合适的构造函数?

至于避免虚假通知,有几个潜在的解决方案:

  • 限制对设置器的访问以保留它们以供任何持久性/序列化机制使用,并为系统的其余部分使用一组不同的方法。例如,您可以执行以下操作:

    公共类文本 { long privateId; ...私有 setPrivateId(long x) { privateId = x; }

    public setId(long x) {
       setPrivateId(x);
    
       this.triggerChangeNotifiers();
    }
    ...
    

    }

  • 让 Hibernate 直接填写字段,而不通过设置器 - 我相信有很多注释,但请记住,这种方法可能会使未来的重构更加困难。

于 2012-11-15T13:46:48.110 回答