【问题标题】:Modelling a temporal-style relational table in Hibernate在 Hibernate 中建模时间样式的关系表
【发布时间】:2009-12-01 16:57:02
【问题描述】:

我正在尝试将 Hibernate 包裹在现有的数据模型上,正如预期的那样,它有起有落。

我目前的症结是其中一个实体表具有准时态模型;没有行被删除或更新;而是将“is_current”列设置为 false(并使用更新时的新字段创建新行,并使用不同的主键)。

对 Hibernate 来说相对较新,我正在努力研究如何建模,甚至确定它是否可能。好吧,使用自定义 @SQLDelete 注释,删除很简单,但更新看起来很棘手。从理论上讲,这似乎可能是一件非常简单的事情(在元代码中,@SQLUpdate(sql = @SQLDelete + "; " + @SQLInsert))但有明显的复杂性(除了这种语法不存在的事实),部分围绕这样一个事实,即需要在两个语句之间取消主键并在第二个语句中进行更新,我确信还有其他数据一致性问题我还没有考虑过。

有没有一种现实的方法来管理这个,即模型更新为 Hibernate 中的删除 + 插入?

编辑:澄清一下,我知道我可以通过显式指定插入 SQL,然后使用上面的 sn-p(对 SQL 常量的合法引用)以蛮力的方式让它工作进行更新。但是,我真的不想这样做,因为我很高兴 SQL Hibernate 选择默认为插入生成,如果类发生变化,手动写出来会非常脆弱。这是强制执行此操作的最后一个解决方案,但如果我必须手动编写 SQL,它似乎会在某种程度上破坏 ORM 映射器的意义......

双重编辑:即使上述内容也可能不起作用,因为我需要在 SQL 中指定两次主键绑定参数(不可能使用问号),并且我无法说服Hibernate 从 SequenceGenerator 中分​​配给我一个新的。所以看起来我需要一种编程方法,而不是配置方法——除非我错过了一些特别相关的配置元素。

【问题讨论】:

    标签: hibernate


    【解决方案1】:

    您说没有更新任何行,但听起来您正在更新该行的 is_current 列。我会使用 Hibernate 做同样的事情(更新行的 isCurrent 字段,然后创建一个新行),而不是尝试编写一个实际上是更新的自定义删除函数。

    row1.setCurrent(false);
    session.saveOrUpdate(row1);
    row2 = new Row(row1); //Copy constructor; use a different primary key (or your default primary key for a new object)
    row2.setCurrent(true);
    row2.setFoo("bar"); //whatever data updates you are doing for the new row
    session.saveOrUpdate(row2);
    

    您可以将此过程包装在一些中间层/业务逻辑代码中,以确保不会更新其他字段。

    【讨论】:

    • 重点是能够做到这一点,而不必以这种方式更改客户端代码。当前定制的(不是很好的)数据存储层通过实现更新来实现这一点,基本上是delete(); insert();,我想说服 Hibernate 做同样的事情。
    • 我不确定这是否可能。在 Hibernate 会话的上下文中,数据库中的每条记录都映射到 Java 中持久对象的不同实例。更新是针对同一实例的操作; delete 和 insert 对两个不同的数据库行(因此,两个不同的对象)进行操作。 AFAIK,您不能使用相同的持久对象操作两个不同的数据库记录。使用中间层,您可以使用一个“业务对象”在后台处理两个 Hibernate 对象。我不知道是否有办法绕过这个限制。
    【解决方案2】:

    我们有一个与 Hibernate 一起使用的完全时间星型模式。然而,Hibernate 永远不知道审计表或事实表,而只知道表的视图。这允许我们像往常一样使用 Hibernate,因此当 Hibernate 在数据库中的视图上发出插入、删除或更新时,会为这些相应的任务触发“而不是”触发器。

    因此,在您的情况下,创建一个视图(Hibernate 不知道更好,并且是完全透明的)和适当的触发器来设置您的标志和其他任何东西。实际上,我很惊讶我们是如何以相对较小的痛苦摆脱这个问题的——而且我们的设计确实可以更好,因为使用 Hibernate 是事后才想到的/添加的。

    【讨论】:

      【解决方案3】:

      进一步研究了这一点,我相信不会有一个简单的方法来做到这一点。我很想尝试的一种方法是将原始表隐藏在可更新视图后面,以便在视图上的触发器将简单的 CRUD 操作映射到基础表中所需的操作序列时,可以向 Hibernate 呈现看起来很正常的东西.

      但是,我怀疑这可能效果不佳,因为我相信 Hibernate 在任何时间点都保持自己的数据库内容概念;例如如果我删除一个实体,Hibernate 的缓存会认为该物理行不再存在于表中(虽然它确实存在,但 is_current 现在为 false)。如果这种不匹配可能导致最坏情况下的数据一致性问题,或者可能导致批处理优化效率低下,我不会感到惊讶。

      无论如何,现有的表格都很糟糕,所以在这种变化的背景下让它们更加理智是我将要采取的方法。至少这个评估阶段让现有模型的一些不足之处更加清晰。

      【讨论】:

        猜你喜欢
        • 2014-04-05
        • 2010-09-23
        • 2019-07-10
        • 2021-05-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多