我们有两个实体,如Resource和NonFTECast。而我们之间的关系是OneToMany双向的。以下是实体
@Getter
@Setter
@NoArgsConstructor
@Entity
@Table
public class Resource {
@NotNull
@Column(name = "NAME", nullable = false, length = 255)
@Audited(withModifiedFlag = true)
private String name;
@OneToMany(mappedBy = "resource", cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
@Audited
private List<NonFTECost> costings = new ArrayList<>();
//other fields
}
@Getter
@Setter
@Table
@Entity
public class NonFTECost {
@NotNull
@Audited(withModifiedFlag = true, modifiedColumnName = "PAYMENT_MOD")
private Payment payment;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "RESOURCE_CODE", nullable = false, foreignKey = @ForeignKey(name = FK_COST_DETAILS_RESOURCE_CODE))
@Audited(withModifiedFlag = true, modifiedColumnName = "RESOURCE_CODE_MOD", targetAuditMode = RelationTargetAuditMode.AUDITED)
private Resource resource;
//other fields
}
现在我创建了一个带有成本的资源,然后它将为每个审计表创建新的修订。然后我只更改了NonFTECost实体的付款字段,它将在NonFTECost_Aud表中创建新的修订(这也是资源更新的一部分(。
问题:-在获得资源的修订时,我想获得该特定资源实体的非全职员工成本的修订。因为我想向用户显示类似fieldName oldvalue newvalue
请帮我解决这个问题。
您应该能够通过在查询的特定修订实例上迭代该集合来获取Resource
的给定修订的关联NonFTECost
实体。
例如,假设我对Resource
的第5版感兴趣
final Number revision = 5;
final AuditReader auditReader = auditReaderFactory.get( session );
final Resource resource = auditReader.find( Resource.class, resourceId, revision );
for ( Cost cost : resource.getCosts() ) {
// do whatever with cost
}
现在,您需要的是如何获取Cost
实例并找出发生了什么变化。由于您使用了withModifiedFlags=true
功能,因此我们可以特别使用forRevisionsOfEntityWithChanges
。
我想指出的一件事是,在您的映射场景中,如果您碰巧在没有专门针对Resource
进行修改的事务中修改成本实体,那么NonFTECost
实体的修订可能比Resource
的修订更高。
考虑到这一点,您需要在for循环逻辑中说明这一点。因此,在该循环中,我们需要基于Cost
实例执行查询,并单独获取其修订历史记录。
// This list is an object array that contains the following
// Index 0 - The `Cost` entity again at the revision
// Index 1 - The revision entity (contains revision number/timestamp)
// Index 2 - The RevisionType: ADD, MOD, or DEL
// Index 3 - Set<String> of property names that changed at this revision
List results = auditReader.createQuery()
.forRevisionsOfEntityWithChanges( Cost.class, false )
.add( AuditEntity.id().eq( cost.getId() ) )
.addOrder( AuditEntity.revisionNumber().desc() )
.setMaxResult( 2 )
.getResultList();
如果结果列表只包含1行,那么您知道一些事情(假设没有数据修剪(
- 索引2应为RevisionType.ADD
- 索引3包含在原始持久化期间设置的字段的
Set<String>
- 没有任何字段具有旧值,无论其插入持久值是什么
如果结果列表包含2行,那么这就是您需要处理新旧值逻辑的地方。你应该能够做这样的事情:
if ( results.size() == 2 ) {
Object[] newArray = (Object[]) results.get( 0 );
Object[] oldArray = (Object[]) results.get( 1 );
Set<String> propertiesChanged = (Set<String>) newArray[3];
for ( String propertyName : propertiesChanged ) {
if ( "value".equals( propertyName ) ) {
Double newValue = ( (NonFTECost) newArray[0] ).getValue();
Double oldValue = ( (NonFTECost) oldArray[1] ).getValue();
}
}
}
else if ( results.size() == 1 ) {
Object[] array = (Object[]) results.get( 0 );
Set<String> propertiesChangedOnInsert = (Set<String>) array[3];
// do whatever here
}
这不是最优雅的解决方案,但它很有效。