欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring Data MongoDB中实现自定义级联的方法详解

程序员文章站 2024-04-01 22:23:52
前言 spring data mongodb 项目提供与mongodb文档数据库的集成,spring与hibernate集成时,spring提供了org.springfr...

前言

spring data mongodb 项目提供与mongodb文档数据库的集成,spring与hibernate集成时,spring提供了org.springframework.orm.hibernate3.hibernatetemplate实现了对数据的crud操作, spring data mongodb提供了org.springframework.data.mongodb.core.mongotemplate对mongodb的crud的操作,包括对集成的对象映射文件和pojo之间的crud的操作。

在使用spring data操作mongodb中:

  • 在保存一个实体的时候,如果被@dbref标识的类只传入id,保存后返回的结果并没有全部的引用类内容,只有id。
  • 保存实体,不能保存引用实体。

例如:我们有一个实体person,有一个实体emailaddress。

@document(collection = "test_person")
public class person {
 private string name;
 @dbref
 private emailaddress emailaddress;
 ... getter setter 方法
}
@document(collection = "test_email")
public class emailaddress {
 @id
 private string id;
 private string value;
 ... getter setter 方法
}

当我们调用保存方法的时候:

public person test() {
 person person = new person();
 person.setname("test");
 emailaddress emailaddress = new emailaddress();
 emailaddress.setid("5a05108d4dcc5dece03c9e69");
 person.setemailaddress(emailaddress);
 testrepository.save(person);
 return person;
}

上述的代码中,返回的person只有id,没有emailaddress的其他值。

public person test() {
 person person = new person();
 person.setname("test");
 emailaddress emailaddress = new emailaddress();
 emailaddress.setname("afafa");
 person.setemailaddress(emailaddress);
 testrepository.save(person);
 return person;
}

上述的代码中,emailaddress不能被保存。

解决

生命周期事件

spring data mongodb中存在一些生命周期事件,如:onbeforeconvert, onbeforesave, onaftersave, onafterload and onafterconvert等。我们可以继承abstractmappingeventlistener,然后重写这些方法,即可以实现。

代码

/**
 * mongodb级联控制
 * created by guanzhenxing on 2017/11/9.
 */
public class cascadecontrolmongoeventlistener extends abstractmongoeventlistener<object> {
 @autowired
 private mongooperations mongooperations;
 @override
 public void onaftersave(aftersaveevent<object> event) {
 super.onaftersave(event);
 object source = event.getsource();
 reflectionutils.dowithfields(source.getclass(), new cascadeaftersavecallback(source, mongooperations));
 }
 @override
 public void onbeforeconvert(beforeconvertevent<object> event) {
 super.onbeforeconvert(event);
 object source = event.getsource();
 reflectionutils.dowithfields(source.getclass(), new cascadebeforeconvertcallback(source, mongooperations));
 }
}
/**
 * 级联控制的回调
 * created by guanzhenxing on 2017/11/10.
 */
public class cascadeaftersavecallback implements reflectionutils.fieldcallback {
 private object source;
 private mongooperations mongooperations;
 public cascadeaftersavecallback(final object source, final mongooperations mongooperations) {
  this.source = source;
  this.mongooperations = mongooperations;
 }
 @override
 public void dowith(final field field) throws illegalargumentexception, illegalaccessexception {
  reflectionutils.makeaccessible(field);
  if (field.isannotationpresent(dbref.class)) {
   final object fieldvalue = field.get(source); //获得值
   if (fieldvalue != null) {
    docascadeload(field);
   }
  }
 }
 /**
  * 级联查询
  *
  * @param field
  */
 private void docascadeload(field field) throws illegalaccessexception {
  object fieldvalue = field.get(source);
  list<field> idfields = reflectionutil.getannotationfield(fieldvalue, id.class); //该方法是为了获得所有的被@id注解的属性
  if (idfields.size() == 1) { //只处理一个id
   object idvalue = reflectionutil.getfieldvalue(fieldvalue, idfields.get(0).getname());
   object value = mongooperations.findbyid(idvalue, fieldvalue.getclass()); //查询获得值
   reflectionutil.setfieldvalue(source, field.getname(), value);
  }
 }
}
public class cascadebeforeconvertcallback implements reflectionutils.fieldcallback {
 private object source;
 private mongooperations mongooperations;
 public cascadebeforeconvertcallback(object source, mongooperations mongooperations) {
  this.source = source;
  this.mongooperations = mongooperations;
 }
 @override
 public void dowith(field field) throws illegalargumentexception, illegalaccessexception {
  reflectionutils.makeaccessible(field);
  if (field.isannotationpresent(dbref.class)) {
   final object fieldvalue = field.get(source); //获得值
   if (fieldvalue != null) {
    docascadesave(field);
   }
  }
 }
 /**
  * 级联保存
  *
  * @param field
  * @throws illegalaccessexception
  */
 private void docascadesave(field field) throws illegalaccessexception {
  if (field.isannotationpresent(cascadesave.class)) { //如果有标识@cascadesave注解
   object fieldvalue = field.get(source);
   list<field> idfields = reflectionutil.getannotationfield(fieldvalue, id.class);
   if (idfields.size() == 1) {
    mongooperations.save(fieldvalue);
   }
  }
 }
}
@retention(retentionpolicy.runtime)
@target(elementtype.field)
public @interface cascadesave {
}
@configuration
public class mongoconfig {
 @bean
 public cascadecontrolmongoeventlistener usercascadingmongoeventlistener() {
  return new cascadecontrolmongoeventlistener();
 }
}

以上是核心代码。至此,我们就可以解决上述的问题了。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。

参考:http://www.baeldung.com/cascading-with-dbref-and-lifecycle-events-in-spring-data-mongodb