我的应用程序使用Hibernate-Envers 4.3.11
目前我通过获取Song的第一个版本并将其保存的数据复制到最新版本的Song来实现此目的。但有没有办法我可以说这个早期版本并将其作为最新版本。
更新
我现在正在实施纳罗斯的答案。所以现在我有一个名为SongFile的类,它总是代表磁盘上音乐文件的内容,这是@Audited(由Envers提供),主要ID是@GeneratedValue。
然后我们有一个名为Song的类,在创建一个SongFile实体后,我们创建一个等效的Song实体。这不会被审核,主要ID是手动设置的,我们将primaryId和所有元数据设置为与Song类相同。
然后,应用程序将元数据修改为Song。
然后在结束时如果处于预览模式,我们只是比较Song和SongFile之间的差异并生成报告。
如果在Real保存模式下,我们比较Song和SongFile之间的差异并生成报告并将更改保存回文件和SongFile。
这很有效,解决了许多问题。
但是我有一个问题,音乐文件也可以存储多个图像(jpeg等),我们用表示图像的CoverImage类来模拟它,而一个CoverArt类在Song和CoverImage之间提供1:M链接,还存储一个名称属性。
现在的问题是我创建了一个由SongFile使用的CoverArtFile类,它使用@GeneratedValue和Song使用的不自动的CoverArt类。
当最初加载文件并创建SongFile和Song时,这可以正常工作,将自动化值从任何CoverArtFile
类复制到CoverArt类
但是,如果我们没有开始使用它然后它被应用程序添加我们就会失败,因为CoverArt类不会自动生成主键,并且我无法安全地生成一个以防它被现有的CoverArtFile类使用(或者将在未来)。
如果我有使用自动值的CoverArt,那么它不会与其关联的CoverArtFile类使用的值相同。
我该怎么办?
首先,没有自动方式来执行您的请求。此过程必须完全手动并在应用程序中进行编码,因为有许多实体细微差别和业务考虑因素最好由应用程序决定和处理。
所以最好的方法就是这样做
可能有用的另一个想法是考虑分离预览和非预览的概念。我的意思是你有两个实体而不是一个Song
。你有一个代表高度的voltile版本用于预览,另一个代表用于表示文件内容的较少的voltile非预览版本。
在这种方法中,当您修改预览变体时,您只需创建一个包含Envers的更改日志,以获取可能对文件进行但不是由于预览模式的内容。修改非预览变量时,您将为文件内容创建更改日志。
这里需要注意的是你的业务逻辑应该也可以在这个用例中同步预览变量,这样预览和非预览都有相同的内容,所以基本上加载预览实体,修改它以匹配非预览然后保存更改也是如此。
如果两种实体类型都具有公共主键或自然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
)维护与文件侧的关系,或者存储关联实体的标识符,以便您可以确定是否需要获取/复制或构造/插入。