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