我实现了基于spring数据和mongodb的应用程序。
@Document(collection = "QATemplate")
public class QATemplate {
@Id
private String titleId;
public String getTitleId() {
return titleId;
}
public void setTitleId(String titleId) {
this.titleId = titleId;
}
@Field("title")
private String title;
@Field("tags")
private Object tags;
@Field("answer_type")
private String answerType;
@Field("answer")
@DBRef
@CascadeSave
private Object answer;
我有一个可以是简单文本的字段,也可以是嵌入文档。 所以我创建了该字段作为对象类型。
@Field("answer")
private Object answer;
工作得很好。 但我需要用自己的id保存嵌入式文档,并将其id作为参考传递给本文档,所以我必须像这样写我的代码
@Field("answer")
@DBRef
@CascadeSave
private Object answer;
用于实现我使用的级联保存
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CascadeSave {
}
public class CascadeCallback implements ReflectionUtils.FieldCallback {
private Object source;
private MongoOperations mongoOperations;
public CascadeCallback(final Object source, final MongoOperations mongoOperations) {
this.source = source;
this.setMongoOperations(mongoOperations);
}
@Override
public void doWith(final Field field) throws IllegalArgumentException, IllegalAccessException {
ReflectionUtils.makeAccessible(field);
if (field.isAnnotationPresent(DBRef.class) && field.isAnnotationPresent(CascadeSave.class)) {
final Object fieldValue = field.get(getSource());
boolean insta = !(fieldValue instanceof String);
boolean instanull = fieldValue != null;
if ( instanull && insta ) {
final FieldCallback callback = new FieldCallback();
ReflectionUtils.doWithFields(fieldValue.getClass(), callback);
getMongoOperations().save(fieldValue);
}
}
}
public Object getSource() {
return source;
}
public void setSource(final Object source) {
this.source = source;
}
public MongoOperations getMongoOperations() {
return mongoOperations;
}
public void setMongoOperations(final MongoOperations mongoOperations) {
this.mongoOperations = mongoOperations;
}
}
public class CascadeSaveMongoEventListener extends AbstractMongoEventListener<Object> {
@Autowired
private MongoOperations mongoOperations;
@Override
public void onBeforeConvert(final Object source) {
ReflectionUtils.doWithFields(source.getClass(), new CascadeCallback(source, mongoOperations));
}
}
public class FieldCallback implements ReflectionUtils.FieldCallback {
private boolean idFound;
@Override
public void doWith(final Field field) throws IllegalArgumentException, IllegalAccessException {
ReflectionUtils.makeAccessible(field);
if (field.isAnnotationPresent(Id.class)) {
idFound = true;
}
}
public boolean isIdFound() {
return idFound;
}
}
但在应用此代码后如果我插入像这样的json数据
{
"title":"Indiaa",
"answerType":"text",
"answer":[
{
"title":"Indiaana jones",
"answerType":"text",
"answer":"testing vvv"
}
]
}
我收到了一个错误:
threw exception [Request processing failed;
nested exception is java.lang.ClassCastException: com.mongodb.BasicDBObject cannot be cast to com.mongodb.BasicDBList] with root cause
java.lang.ClassCastException: com.mongodb.BasicDBObject cannot be cast to com.mongodb.BasicDBList
如果我尝试插入这样的json数据:
{
"title":"Indiava",
"answerType":"text",
"answer":"vv"
}
我收到了一个错误:
HTTP Status 500 - Request processing failed;
nested exception is org.springframework.data.mapping.model.MappingException: No mapping metadata found for class java.lang.String
答案 0 :(得分:1)
使用DBRef
时,不是将answer
对象保存在QATemplate
内,而是仅保存对它的引用,但它位于另一个集合中:
{ "$ref" : "COLLECTION", "$id" : ObjectId("someobjectID") }
此外,你说你想要一个答案“文档”,但你实际上先传递一个数组,然后传递一个简单的字符串。
要使其运行,请创建一个包含答案文档和字符串答案的类型。这样Spring Data MongoDB
将知道在哪个集合中放置它。首先尝试使用一个文档,如下所示:
{
"title":"Where is India",
"answerType":"text",
"answer":{
"text":"Asia"
}
}
answer
的位置:
@Field("answer")
@DBRef
@CascadeSave
private Answer answer;
Answer
是:
@Document(collection = "Answers")
public class Answer {
@Id
private String id;
String text;
}
运行此功能后,将Answer
转换为界面,然后设置TextAnswer
(简单文本)或FullAnswer
(整个答案文档)。 Spring Data MongoDB
支持多态性。