Spring Data MongoDB中实现自定义级联的方法详解
前言
SpringDataMongoDB项目提供与MongoDB文档数据库的集成,Spring与Hibernate集成时,Spring提供了org.springframework.orm.hibernate3.HibernateTemplate实现了对数据的CRUD操作,SpringDataMongoDB提供了org.springframework.data.mongodb.core.MongoTemplate对MongoDB的CRUD的操作,包括对集成的对象映射文件和POJO之间的CRUD的操作。
在使用SpringData操作MongoDB中:
- 在保存一个实体的时候,如果被@DBRef标识的类只传入Id,保存后返回的结果并没有全部的引用类内容,只有Id。
- 保存实体,不能保存引用实体。
例如:我们有一个实体Person,有一个实体EmailAddress。
@Document(collection="test_person") publicclassPerson{ privateStringname; @DBRef privateEmailAddressemailAddress; ...gettersetter方法 }
@Document(collection="test_email") publicclassEmailAddress{ @Id privateStringid; privateStringvalue; ...gettersetter方法 }
当我们调用保存方法的时候:
publicPersontest(){ Personperson=newPerson(); person.setName("test"); EmailAddressemailAddress=newEmailAddress(); emailAddress.setId("5a05108d4dcc5dece03c9e69"); person.setEmailAddress(emailAddress); testRepository.save(person); returnperson; }
上述的代码中,返回的person只有id,没有emailAddress的其他值。
publicPersontest(){ Personperson=newPerson(); person.setName("test"); EmailAddressemailAddress=newEmailAddress(); emailAddress.setName("afafa"); person.setEmailAddress(emailAddress); testRepository.save(person); returnperson; }
上述的代码中,emailAddress不能被保存。
解决
生命周期事件
SpringDataMongoDB中存在一些生命周期事件,如:onBeforeConvert,onBeforeSave,onAfterSave,onAfterLoadandonAfterConvert等。我们可以继承AbstractMappingEventListener,然后重写这些方法,即可以实现。
代码
/** *MongoDB级联控制 *Createdbyguanzhenxingon2017/11/9. */ publicclassCascadeControlMongoEventListenerextendsAbstractMongoEventListener
/** *级联控制的回调 *Createdbyguanzhenxingon2017/11/10. */ publicclassCascadeAfterSaveCallbackimplementsReflectionUtils.FieldCallback{ privateObjectsource; privateMongoOperationsmongoOperations; publicCascadeAfterSaveCallback(finalObjectsource,finalMongoOperationsmongoOperations){ this.source=source; this.mongoOperations=mongoOperations; } @Override publicvoiddoWith(finalFieldfield)throwsIllegalArgumentException,IllegalAccessException{ ReflectionUtils.makeAccessible(field); if(field.isAnnotationPresent(DBRef.class)){ finalObjectfieldValue=field.get(source);//获得值 if(fieldValue!=null){ doCascadeLoad(field); } } } /** *级联查询 * *@paramfield */ privatevoiddoCascadeLoad(Fieldfield)throwsIllegalAccessException{ ObjectfieldValue=field.get(source); ListidFields=ReflectionUtil.getAnnotationField(fieldValue,Id.class);//该方法是为了获得所有的被@Id注解的属性 if(idFields.size()==1){//只处理一个Id ObjectidValue=ReflectionUtil.getFieldValue(fieldValue,idFields.get(0).getName()); Objectvalue=mongoOperations.findById(idValue,fieldValue.getClass());//查询获得值 ReflectionUtil.setFieldValue(source,field.getName(),value); } } }
publicclassCascadeBeforeConvertCallbackimplementsReflectionUtils.FieldCallback{ privateObjectsource; privateMongoOperationsmongoOperations; publicCascadeBeforeConvertCallback(Objectsource,MongoOperationsmongoOperations){ this.source=source; this.mongoOperations=mongoOperations; } @Override publicvoiddoWith(Fieldfield)throwsIllegalArgumentException,IllegalAccessException{ ReflectionUtils.makeAccessible(field); if(field.isAnnotationPresent(DBRef.class)){ finalObjectfieldValue=field.get(source);//获得值 if(fieldValue!=null){ doCascadeSave(field); } } } /** *级联保存 * *@paramfield *@throwsIllegalAccessException */ privatevoiddoCascadeSave(Fieldfield)throwsIllegalAccessException{ if(field.isAnnotationPresent(CascadeSave.class)){//如果有标识@CascadeSave注解 ObjectfieldValue=field.get(source); ListidFields=ReflectionUtil.getAnnotationField(fieldValue,Id.class); if(idFields.size()==1){ mongoOperations.save(fieldValue); } } } }
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public@interfaceCascadeSave{ }
@Configuration publicclassMongoConfig{ @Bean publicCascadeControlMongoEventListeneruserCascadingMongoEventListener(){ returnnewCascadeControlMongoEventListener(); } }
以上是核心代码。至此,我们就可以解决上述的问题了。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。
参考:http://www.baeldung.com/cascading-with-dbref-and-lifecycle-events-in-spring-data-mongodb