我的应用程序使用Hibernate-Envers 4.3.11
当前,我通过获取Song的第一个修订版并将其保存的数据复制到Song的最新版本中来进行此操作。 但是我只能说采用此较早的修订并使其成为最新的修订。
更新
我现在正在执行Naros的答案。因此,现在我有了一个名为 SongFile 的类,该类始终表示磁盘上音乐文件的内容,这是@Audited(由Envers提供),主要ID是@GeneratedValue。
然后,我们创建了一个名为 Song 的类,在创建了 SongFile 实体并将其省略后,我们创建了一个等效的 Song 实体。这未经审核,并且手动设置了主要ID,我们将primaryId和所有元数据设置为与Song类相同。
然后,该应用将元数据修改为 Song 。
然后得出结论,如果处于 Preview模式,我们只需比较 Song 和 SongFile 之间的差异并生成报告即可。
如果处于真实保存模式,我们将比较 Song 和 SongFile 之间的差异,并生成报告并将更改保存回文件中,然后 SongFile 。
这很好用,并且解决了许多问题。
但是,如果我遇到问题,音乐文件也可以存储多个图像(jpeg等),我们使用表示图像的 CoverImage 类和用于表示图像的 CoverArt 类对此进行建模提供 Song 和 CoverImage 之间的1:M链接,还存储了name属性。
现在的问题是,我创建了一个 SongFile 使用的 CoverArtFile 类,该类使用@GeneratedValue和一个使用的 CoverArt 类不会自动生成的歌曲。
最初加载文件并创建 SongFile 和 Song 时,此方法可以正常工作,将自动生成的值从任何CoverArtFile
类复制到 CoverArt < / em>类
但是,如果我们没有Coverart开头,然后又被应用程序添加,则会失败,因为 CoverArt 类不会自动生成主键,如果使用它,我将无法安全地生成一个主键由现有的 CoverArtFile 类(或将来的版本)提供。
如果我有一个使用自动生成的值的CoverArt,那么它将不会与其关联的CoverArtFile类所使用的值相同。
我该如何进行?
答案 0 :(得分:1)
首先,没有自动方法可以完成您所要求的操作。该过程必须完全手动进行并在应用程序中进行编码,因为存在许多实体差异和业务注意事项,最好由应用程序来决定和处理。
所以最好的方法是
另一个可行的想法是考虑将预览和非预览的概念分开。我的意思是您有两个实体,而不是一个Song
。您有一个代表 preview 的高度易失版本,另一个代表不易波动的 non-preview ,其意为表示文件内容。
在这种方法中,当您修改 preview 变体时,您只是使用Envers创建了一个更改日志,以查找可能是由于该文件而并非由于 preview-模式。修改非预览版变体时,您正在为文件内容应创建一个更改日志。
需要注意的是,在这种用例中,您的业务逻辑可能还应该同步 preview 变体,以使 preview 和 non-preview em>具有相同的内容,因此基本上加载 preview 实体,对其进行修改以匹配 non-preview ,然后也保存对其所做的更改。
如果两种实体类型都具有通用的主键或自然ID,则这应该易于管理,并允许您生成所有类型的报告并保持一致的历史记录,而无需担心。
添加到我关于您的更新的答案中;在这里,您可能希望对所有实体使用生成的标识符,并使Song
和CoverArt
实体维护对已审计实体的引用,或者至少存储主键值。>
例如
@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
)或存储关联实体的标识符来保持与文件端的关系,以便您可以确定是否需要获取/复制或构造/插入。