【问题标题】:In Hibernate-Envers how to make earlier revison of an entity the latest revision在 Hibernate-Envers 中,如何使实体的早期版本成为最新版本
【发布时间】:2018-09-05 12:26:54
【问题描述】:

我的应用程序使用 Hibernate-Envers 4.3.11

  • 我将音乐文件加载到我的数据库中,并将它们的元数据(例如专辑标题、艺术家)表示为经过审核的 Song
  • 然后应用程序以各种方式编辑元数据,并写回 Song 类(每次提交的会话都会创建另一个修订版)
  • 然后通常在最后将更改从当前 Song 类写回文件本身。
  • 但如果在预览模式下运行,则不会将任何内容写入文件。因此,我希望该文件的 Song 类的最新版本现在包含与最初加载文件时创建的版本相同的元数据。

目前,我通过获取 Song 的第一个修订版并将其保存的数据复制到 Song 的最新版本来做到这一点。 但有没有一种方法可以让我将这个较早的版本改为最新版本

更新

我现在正在执行 Naros 的答案。所以现在我有一个名为 SongFile 的类,它始终代表磁盘上音乐文件的内容,这是 @Audited(由 Envers 提供),主 ID 是 @GeneratedValue。

然后我们有一个名为Song的类,在创建并省略了一个SongFile实体之后,我们创建了一个等效的Song实体。这个没有审核,primary id是手动设置的,我们设置primaryId和所有的元数据和Song类一样。

然后应用将元数据修改为歌曲

最后,如果在预览模式,我们只是比较SongSongFile之间的差异并生成报告。

如果在 Real save 模式下,我们比较 SongSongFile 之间的差异并生成报告并将更改保存回文件,并且 歌曲文件

效果很好,解决了很多问题。

但是我有一个问题,音乐文件也可以存储多个图像(jpeg 等),我们使用一个表示图像的 CoverImage 类和一个表示图像的 CoverArt 类对其进行建模在 SongCoverImage 之间提供 1:M 链接,还存储了一个名称属性。

现在的问题是我创建了一个 SongFile 使用的 CoverArtFile 类,它使用了@GeneratedValue 和一个 CoverArt 类不会自动生成的歌曲。

最初加载文件并创建 SongFileSong 时,这可以正常工作,将自动生成的值从任何 CoverArtFile 类复制到 CoverArt 班级

但是,如果我们没有开始的封面,然后它被应用程序添加,我们会失败,因为 CoverArt 类不会自动生成主键,我无法安全地生成一个以防万一它被使用通过现有的 CoverArtFile 类(或将在未来)。

如果我让 CoverArt 使用自动生成的值,那么它不会与关联的 CoverArtFile 类使用的值相同。

我该如何进行?

【问题讨论】:

  • 所以在预览模式下,即使不需要这些更改,您也允许事务提交到数据库?
  • 这些更改是(可能)需要的,但只写入数据库而不是文件本身,这样我们就可以创建一个报告,显示如果不在预览模式下运行可能对文件进行的更改.
  • 那么@Naros 有什么想法吗?

标签: java hibernate hibernate-envers


【解决方案1】:

首先,没有自动化的方式来满足您的要求。此过程必须完全手动并在应用程序中编码,因为有许多实体细微差别和业务注意事项最好留给应用程序来决定和处理。

所以最好的方法是

  1. 从您要恢复到的审核历史记录中获取所需的修订。
  2. 从 Hibernate 中获取现有实体。
  3. 将 (2) 中的现有实体中的值设置为 (1) 中获取的所需修订版中的值。
  4. 合并修改后的实体。

另一个可行的想法是考虑将 previewnon-preview 的概念分开。我的意思是你有两个实体而不是一个Song。您有一个代表 preview 的高波动版本,另一个代表用于表示文件内容的波动较小的 non-preview

在这种方法中,当您修改 preview 变体时,您只是使用 Envers 创建一个更改日志,用于记录可能已对文件进行但不是由于 preview-模式。当您修改 non-preview 变体时,您正在为文件内容应该创建一个更改日志。

这里需要注意的是,您的业务逻辑可能还应该同步此用例中的 preview 变体,以便 previewnon-preview em> 具有相同的内容,所以基本上加载 preview 实体,修改它以匹配 non-preview,然后也为它保存更改。

如果两种实体类型都有一个共同的主键或自然 ID,这应该很容易管理,并允许您生成所有类型的报告并保持一致的历史记录而不会混淆问题。

更新

添加关于您的更新的答案;这是您可能希望为所有实体使用生成的标识符并让您的 SongCoverArt 实体保持对被审计实体的引用或至少存储主键值的地方。

举个例子

@Entity
public class Song {
  @Id
  @GeneratedValue
  private Long id;
  @OneToOne
  private SongFile songFile;      
}

或者更简单

@Entity
public class Song {
  @Id
  @GeneratedValue
  private Long id;
  private Long songFileId;
}

这个想法是,您的非基于文件的实体通过关联(例如@OneToOne)或存储关联实体的标识符来维护与文件端的关系,以便您可以确定是否需要获取/复制或构造/插入。

【讨论】:

  • 好的,感谢您确认无法自动完成。我理解您的替代想法,但是预览的起点是文件的现有内容(non_preview),因此在第一次加载文件并创建歌曲之后,如果不是预览模式,我将不得不在最后阶段创建预览并复制数据我将不得不重新复制。所以我不确定这是否比我目前拥有的更好,但我会进一步考虑。
  • 嗯,我认为这是一个好主意,但由于歌曲确实与其他一些也需要复制的数据 (CoverArt) 存在某种 1:M 关系,这一事实使情况变得复杂。
  • 我正在实施您的解决方案,因为我认为它可以解决许多问题,但是我遇到了 CoverArt 的问题。我已按问题更新,希望您能帮助我。
  • @PaulTaylor 请查看我的更新,如果这解决了您最近对该方法的担忧,请告诉我。
  • 我不需要为 Song 课这样做,但是好吧我已经在想我必须自动生成 CoverArt Id,这确实提供了一种跟踪方法,尽管不像 Song 那样简单类。
猜你喜欢
  • 2023-03-04
  • 2010-10-22
  • 2012-07-29
  • 1970-01-01
  • 1970-01-01
  • 2012-11-11
  • 1970-01-01
  • 2019-12-13
  • 2020-04-25
相关资源
最近更新 更多