[英]Update Couchbase documents without overwriting @Created fields with Spring Data Auditing
我有一个 Couchbase 文档,我想为其启用审计:
@Document(expiry = 0, expiryUnit = TimeUnit.DAYS, touchOnRead = true)
public class Entity {
@Id
@GeneratedValue(strategy = GenerationStrategy.USE_ATTRIBUTES, delimiter = ":")
private String id;
@IdAttribute(order = 0)
private String type;
@IdAttribute(order = 1)
private String entityGuid;
@Version
private long version;
private String firstName;
private String lastName;
private LocalDate dateOfBirth;
@CreatedDate
private LocalDateTime createTimeStamp;
@LastModifiedDate
private LocalDateTime lastUpdateTimeStamp;
@CreatedBy
private String createdBy;
@LastModifiedBy
private String lastUpdatedBy;
...
我的配置:
@Data
@Configuration
@EnableCouchbaseAuditing
@EnableConfigurationProperties(CouchbaseProperties.class)
public class EntityCouchConfig extends AbstractCouchbaseConfiguration {
...
@Bean
public AuditorAware<String> couchAuditing() {
return () -> Optional.of("my-entity-service");
}
}
我期望在通过 Couchbase 模板执行更新操作时,如replaceById()
和upsertById()
,spring-data 将保留文档的@CreatedDate
和@CreatedBy
字段,仅更新@LastModifiedDate
和@LastModifiedBy
。
然而,情况似乎并非如此。 当我执行更新时,文档的@Created
字段也会更新。 这似乎违反直觉,并建议我首先需要提取文档,传输@Created
字段,然后保存它,明确地进行两次调用。
我已经阅读了关于审计的 spring-data-couchbase 文档,但这里的预期行为非常少。
是检索文档以捕获创建信息然后更新执行此操作的唯一方法,还是我实施审计错误?
所以我的问题是基于一个有缺陷的前提,因为执行像upsert()
和replaceById()
这样的 Couchbase 模板操作永远不会执行任何审计逻辑。
要使审计工作,它必须与 Couchbase Repository的save()
方法结合使用。
另一个重要的一点是,如果您的调用者想要更新实体并且没有当前版本号和当前审计数据,则审计不会取消对数据库的两次调用。
为了使 spring-data 审计能够处理更新操作,您必须提供一个具有所有审计字段(@CreatedDate/By、@LastModifiedDate/By)和当前版本号的实体。 这意味着如果您的调用者没有此信息,您必须执行查找调用以检索它,然后在将该数据添加到您的实体后进行保存。 只有这样,审计才会在更新@Lastxx
字段时智能地保留原始@Createdxx
字段。
“所以我的问题是基于一个有缺陷的前提,因为执行像 upsert() 和 replaceById() 这样的 Couchbase 模板操作永远不会执行任何审计逻辑。
要使审计工作,它必须与 Couchbase 存储库的 save() 方法结合使用。”
repository.save() 调用 template.save() ,后者又调用 insertById、replaceById 或 upsertById 之一(取决于 @Version 字段的存在,以及它是否被填充)。
所有 couchbase 修改操作插入/更新插入/替换在 spring 数据 couchbase 中调用 - ReplaceByIdOperationSupport.one(), InsertByIdOperationSupport().one, UpsertByIdOperationSupport.one() 使用 ReactiveCouchbaseTemplateSupport.encodeEntity() 转换实体,在 onBeforeConvert 中进行审计(). 设置 org.springframework.data.couchbase.core.mapping.event=TRACE 的日志记录来查看。
“如果您的调用者想要更新一个实体并且没有当前版本号和当前审计数据。”
所有插入/替换/更新操作都作用于整个文档。 所以当你更新插入时,你会覆盖所有内容,如果你还没有当前的审计数据,你会覆盖它们。 如果您没有当前版本号,但您的实体有一个@Version 字段,您可以将其保留为空或 0,并且 repository.save() 将调用 template.save(),后者将调用 template.upsertById。
markedAudit() 方法如下。 如果实体没有@Version 或@Version 字段为空或零,则isNew() 为真。
public Mono<Object> markAudited(Object object) {
Assert.notNull(object, "Source object must not be null");
if (!this.isAuditable(object)) {
return Mono.just(object);
} else {
PersistentEntity<?, ? extends PersistentProperty<?>> entity = this.entities.getRequiredPersistentEntity(object.getClass());
return entity.isNew(object) ? this.markCreated(object) : this.markModified(object);
}
}
“您必须执行查找调用以检索它,然后在将该数据添加到您的实体后进行保存。只有这样,审计才能在更新@Lastxx 字段时智能地保留原始@Createdxx 字段。”
所以最终的评估非常正确,尽管它应该通过 repository.save()、template.insertById() 和 template.replaceById() 和 template.upsertById() 同样有效。 (但如果您已经获取了文档,您的实体将具有 @Version 并且无需使用 upsert() 而不是 replace()。
唯一奇怪的行为是,如果您有一个没有@Version 的实体,但它有一个@Createdxxxx,它将始终将其视为新实体——因为它没有@Version 以其他方式指示。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.