zou*_*oto 5 spring-data spring-data-mongodb
使用 spring 数据 mongo,我需要更新 mongo 中的文档。
我的实体是这样定义的:
@Document(collection = "Orders")
public class Order{
@Id
private Long id;
private String clientContainerReference;
private String status;
private Bigdecimal amount;
private BigDecimal remainingQuantity;
...
}
Run Code Online (Sandbox Code Playgroud)
首先,这个文档被插入到 mongo 中,剩余数量为 100。接下来,订单被更新为空剩余数量。更新(upsert)后,residualQuantity 始终设置为 100。
这是由于类:
org.springframework.data.mongodb.core.convert.MappingMongoConverter
Run Code Online (Sandbox Code Playgroud)
在 writeInternal 方法中,对文档的每个属性都进行了空检查。如果该属性为空,则从生成的 DBObject 中排除它。
entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
public void doWithPersistentProperty(MongoPersistentProperty prop) {
if (prop.equals(idProperty)) {
return;
}
Object propertyObj = wrapper.getProperty(prop);
if (null != propertyObj) {
if (!conversions.isSimpleType(propertyObj.getClass())) {
writePropertyInternal(propertyObj, dbo, prop);
} else {
writeSimpleInternal(propertyObj, dbo, prop);
}
}
}
});
Run Code Online (Sandbox Code Playgroud)
我可以理解它更有效,因为生成的 DBObject 更小,更新请求更适合 mongo。但是我怎样才能更新真正的空值呢?
更具体地说,就我而言,所有文档的所有字段都可以为空。所以我不想编写自定义转换器并将每个 java 字段一一映射到 DBObject 字段。
对于更多我的用例,我创建了一个“NullAwareMappingMongoConverter”,它覆盖了 MappingMongoConverter 以让转换器写入该值,如果它是一个空值。
entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
public void doWithPersistentProperty(MongoPersistentProperty prop) {
if (prop.equals(idProperty)) {
return;
}
Object propertyObj = wrapper.getProperty(prop);
if (null != propertyObj) {
if (!conversions.isSimpleType(propertyObj.getClass())) {
writePropertyInternal(propertyObj, dbo, prop);
} else {
writeSimpleInternal(propertyObj, dbo, prop);
}
}
else{
writeSimpleInternal(propertyObj, dbo, prop);
}
}
});
Run Code Online (Sandbox Code Playgroud)
这是一个非常丑陋的解决方案,因为 MappingMongoConverter For spring data mongo 具有包可见性。spring 是否提供了一种方法来告诉:不要使用注释或其他方式忽略此属性上的空值?
谢谢
这是用于更新实体的代码
public T setNotificationDateAndSave(T entity) {
Assert.notNull(entity, "Entity must not be null!");
BasicDBObject dbObject = new BasicDBObject();
mongoTemplate.getConverter().write(entity, dbObject);
DateTime expirationDate = getDeprecatedStatus().contains(getStatus(entity)) ?
new DateTime().plusSeconds(EXPIRE_AFTER_SECONDS) : null;
dbObject.put(EXPIRATION_DATE_COLUMN, mongoTemplate.getConverter()
.convertToMongoType(expirationDate, ClassTypeInformation.from(DateTime.class)));
NotificationDateUpdate update = new NotificationDateUpdate(dbObject, NOTIFICATION_DATE_COLUMN);
Query q = Query.query(Criteria.where("_id").is(entity.getId()).andOperator(Criteria.where(REGISTER_DATE_COLUMN).lte(entity.getRegisterDate())));
try{
mongoTemplate.upsert(q, update, parameterClass);
}catch (DuplicateKeyException e) {
logger.info(format("could not save notification : a more recent notification exists for collection %s and entity id : %s", parameterClass.getName(), entity.getId()));
}
return entity;
}
Run Code Online (Sandbox Code Playgroud)
同样的问题,但我不想弄乱转换器,感觉太复杂了。我只是自动取消对象的所有空字段的设置。
稍微适应您的代码,它看起来像:
DBObject dbObject = new BasicDBObject();
mongoTemplate.getConverter().write(entity, dbObject);
Update update = Update.fromDBObject(dbObject);
for (Field f : entity.class.getDeclaredFields()) {
try {
f.setAccessible(true);
if (f.get(entity) == null)
update.unset(f.getName());
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
ops.upsert(query,update);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2629 次 |
| 最近记录: |