Today, I found a problem that Morphia alwasy stores classname for embedded collection when updating it. Here is my POJO example :
@Entity(noClassnameStored = true)
@Indexes({@Index(name="idx_meta" , value="meta.n, meta.v"), @Index(name="idx_meta_creator", value="meta.c")})
public class ResourceDO {
@Id
private String systemId;
...
@Embedded
private Set<ResourceMetaDO> meta;
...
public Set<ResourceMetaDO> getMetaEntries(){
return meta;
}
}
@Embedded(concreteClass=ResourceMetaDO.class)
public class ResourceMetaDO {
//name
private String n;
//value
private String v;
//creator
private String c;
...
}
I mapped both ResourceDO.class and ResourceMetaDO.class at the startup of my application using Morphia.map().
When I used AdvancedDatastore.save() or AdvancedDatastore.insert() to save or update resource, all went well.
However when I tried to use the following codes to update the meta :
updateMeta( ResourceDO r )
{
Query<ResourceDO> query = ds.createQuery(ResourceDO.class).filter("_id", r.getSystemId() );
UpdateOperations<ResourceDO> update =ds.createUpdateOperations(ResourceDO.class).set("meta", r.getMetaEntries());
dao.getDatastore().update(query, update);
}
The meta was stored with classname. When I looked into UpdateOpsImpl.java :
protected void add(UpdateOperator op, String f, Object value, boolean convert) {
if (value == null)
throw new QueryException("Val cannot be null");
Object val = null;
MappedField mf = null;
if (validateNames || validateTypes) {
StringBuffer sb = new StringBuffer(f);
mf = Mapper.validate(clazz, mapr, sb, FilterOperator.EQUAL, val, validateNames, validateTypes);
f = sb.toString();
}
if (convert)
if (UpdateOperator.PULL_ALL.equals(op) && value instanceof List)
val = toDBObjList(mf, (List<?>) value);
else
val = mapr.toMongoObject(mf, null, value);
...
}
and Mapper.java
public Object toMongoObject(MappedField mf, MappedClass mc, Object value) {
Object mappedValue = value;
//convert the value to Key (DBRef) if the field is @Reference or type is Key/DBRef, or if the destination class is an @Entity
if ((mf!=null && ( mf.hasAnnotation(Reference.class) ||
mf.getType().isAssignableFrom(Key.class) ||
mf.getType().isAssignableFrom(DBRef.class))
) || (mc != null && mc.getEntityAnnotation() != null)) {
try {
Key<?> k = (value instanceof Key) ? (Key<?>)value : getKey(value);
mappedValue = keyToRef(k);
} catch (Exception e) {
log.debug("Error converting value(" + value + ") to reference.", e);
mappedValue = toMongoObject(value, false);
}
}//serialized
else if (mf!=null && mf.hasAnnotation(Serialized.class))
try {
mappedValue = Serializer.serialize(value, !mf.getAnnotation(Serialized.class).disableCompression());
} catch (IOException e) {
throw new RuntimeException(e);
}
//pass-through
else if (value instanceof DBObject)
mappedValue = value;
else {
mappedValue = toMongoObject(value, EmbeddedMapper.shouldSaveClassName(value, mappedValue, mf));
if (mappedValue instanceof DBObject && !EmbeddedMapper.shouldSaveClassName(value, mappedValue, mf))
((DBObject) mappedValue).removeField(CLASS_NAME_FIELDNAME);
}
return mappedValue;
}
and EmbeddedMapper.java
public static boolean shouldSaveClassName(Object rawVal, Object convertedVal, MappedField mf) {
if (rawVal == null || mf == null)
return true;
if (mf.isSingleValue())
return !(mf.getType().equals(rawVal.getClass()) && !(convertedVal instanceof BasicDBList));
else
if ( convertedVal != null &&
convertedVal instanceof DBObject &&
!mf.getSubClass().isInterface() &&
!Modifier.isAbstract(mf.getSubClass().getModifiers()) &&
mf.getSubClass().equals(rawVal.getClass()))
return false;
else
return true;
}
It will always store classname for embedded collection even you have definite concreteClass for the embedded field.
So , I swtiched to the following tagging :
@Entity(noClassnameStored = true)
public class ResourceMetaDO implements IMetaEntry {
@Id
private ObjectId id;
//name
private String n;
//value
private String v;
//creator
private String c;
...
}
It works now. And note the id filed will not be set automatically by morphia if you only use the ResourceMetaDO class as the embedded field of ResourceDO
分享到:
相关推荐
morphia-0.99.jar 最新版本。
这个压缩文件包含mongo-2.7.3.jar和morphia-0.99.jar是morphia框架必须的jar
morphia基于mongodb的基本开发
使用Morphia框架操作mongodb
morphia-1.3.2.jar
mongo-2.7.3.jar和morphia-0.99.jar
spring MVC morphia mongo 整合的例子 网上下载的例子 自己调试保证绝对能运行
Morphia操作MongoDB,进行增删查改操作,内附详细代码。
Mongo的ORM框架的学习Morphia
morphia mongo db OR-mapping mongo db再带的CRUD 太麻烦了, 一个不错的框架 类似 Hibernate
NULL 博文链接:https://hogwartsrow.iteye.com/blog/1471846
后续提交放在https://github.com/zdsiyan/watermelon 上, 用eclipse导入该工程需安装m2eclipse,jetty等查件. 另外.settings下的org.eclipse.wst.common.component文件如下: ...</project-modules>
Morphia开发简介.pdf
中断更改:play-morphia 1.5.0将morphia库更新为org.mongodb.morphia 0.107。 请在您的应用程序中将文本从“ com.google.code.morphia”替换为“ org.mongodb.morphia” PlayMorphia概述 PlayMorphia模块一个功能...
Morphia演示 这是一个简单的测试项目,用于显示一些Morphia功能。要求JDK 7+ Gradle您可以在localhost:27017上使用独立的MongoDB服务器,或者如果该服务器不可用,则测试代码将启动嵌入式MongoDB进程。入门在基本...
使用update方法更新带有@Reference注解的集合字段; 查询包含指定依赖的集合; 对获取的依赖集合添加限制; Morphia获取references的实现; 使用类似关系型数据库的join操作
Morphia/Jackson Java 8 可选示例Morphia (mongoDB) 和 Jackson (JSON) 序列化都可以用来序列化/反序列化新的 Java 8 Optional 类型。 对于 Jackson,您只需要注册 JDK8 模块。 对于 Morphia,您需要为 Optional ...
NULL 博文链接:https://gaozzsoft.iteye.com/blog/1460827
Morphia MongoDB示例 是的对象/文档映射器。 CI
spring-mongodb-morphia springdata-mongo morphia mongodb 学习