【发布时间】:2019-02-13 05:47:22
【问题描述】:
我正在使用 Spring Data 的注释在保存或更新我的实体时将审计数据添加到它们。当我创建实体时,createdBy、createdDate、lastModifiedBy 和 lastModifiedDate 被设置在 repository.save() 返回的对象上。
ResourceEntity(id=ebbe1f3d-3359-4295-8c83-63eab21c4753, createdDate=2018-09-07T21:11:25.797, lastModifiedDate=2018-09-07T21:11:25.797, createdBy=5855070b-866f-4bc4-a18f-26b54f896a4b, lastModifiedBy=5855070b-866f-4bc4-a18f-26b54f896a4b)
不幸的是,当我调用repository.save() 来更新现有实体时,返回的对象没有设置createdBy 和createdDate。
ResourceEntity(id=ebbe1f3d-3359-4295-8c83-63eab21c4753, createdDate=null, lastModifiedDate=2018-09-07T21:12:01.953, createdBy=null, lastModifiedBy=5855070b-866f-4bc4-a18f-26b54f896a4b)
所有字段都在数据库中正确设置,并且在我的服务类之外调用repository.findOne() 会返回一个所有字段设置正确的对象。
ResourceEntity(id=ebbe1f3d-3359-4295-8c83-63eab21c4753, createdDate=2018-09-07T21:11:25.797, lastModifiedDate=2018-09-07T21:12:01.953, createdBy=5855070b-866f-4bc4-a18f-26b54f896a4b, lastModifiedBy=5855070b-866f-4bc4-a18f-26b54f896a4b)
但是,如果我在调用repository.save() 更新实体后立即在服务中调用repository.findOne(),我还会返回一个对象,其中createdBy 和createdDate 设置为null。
这是我的实体:
@Entity(name = "resource")
@EntityListeners(AuditingEntityListener.class)
@Table(name = "resource")
@Data
@EqualsAndHashCode(of = "id")
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ResourceEntity {
@Id
@org.hibernate.annotations.Type(type = "org.hibernate.type.PostgresUUIDType")
private UUID id;
@CreatedDate
@Column(nullable = false, updatable = false)
private LocalDateTime createdDate;
@LastModifiedDate
private LocalDateTime lastModifiedDate;
@CreatedBy
@Column(nullable = false, updatable = false)
@org.hibernate.annotations.Type(type = "org.hibernate.type.PostgresUUIDType")
private UUID createdBy;
@LastModifiedBy
@org.hibernate.annotations.Type(type = "org.hibernate.type.PostgresUUIDType")
private UUID lastModifiedBy;
}
这是我的服务:
@Component
public class ResourceService {
@Autowired
private ResourceRepository resourceRepository;
public ResourceEntity createResource(ResourceEntity resourceEntity) {
return saveResource(resourceEntity);
}
public ResourceEntity updateResource(ResourceEntity resourceEntity) {
return saveResource(resourceEntity);
}
public ResourceEntity getResource(UUID resourceId) {
return resourceRepository.findOne(resourceId);
}
private ResourceEntity saveResource(ResourceEntity resourceEntity) {
ResourceEntity savedResourceEntity = resourceRepository.save(resourceEntity);
return savedResourceEntity;
}
}
这是我的测试:
def "Test update"() {
given:
UUID id = aRandom.uuid()
Resource resource = aRandom.resource().id(id).build()
Resource savedResource = resourceClient.createResource(resource)
when:
Resource updatedResource = aRandom.resource().id(id).build()
updatedResource = resourceClient.updateResource(updatedResource)
then:
Resource result = resourceClient.getResource(id)
assert result.id == updatedResource.id
assert result.createdBy == updatedResource.createdBy
assert result.creationDate == updatedResource.creationDate
assert result.lastModifiedBy == updatedResource.lastModifiedBy
assert result.lastModifiedDate == updatedResource.lastModifiedDate
}
【问题讨论】:
-
这是预期的行为。当设置了 updatable = false 时,你可以更新这个字段。
-
我认为这不是 spring 文档所说的预期行为:保存给定的实体。使用返回的实例进行进一步的操作,因为保存操作可能已经完全改变了实体实例。 如果我们应该使用返回的实例,那么它可以更好地准确地反映数据库中的内容。是的,
update=false阻止save()调用更新创建的字段,但它们应该使用数据库中的内容填充到返回的对象中。 -
对于一个简单的解决方案,您可以再次从数据库中获取实体。现在这个实体将拥有之前更新的字段。
标签: java spring spring-data-jpa auditing