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

2025-05-29 0 34

前言

Spring Data MongoDB 项目提供与MongoDB文档数据库的集成,Spring与Hibernate集成时,Spring提供了org.springframework.orm.hibernate3.HibernateTemplate实现了对数据的CRUD操作, Spring Data MongoDB提供了org.springframework.data.mongodb.core.MongoTemplateMongoDB的CRUD的操作,包括对集成的对象映射文件和POJO之间的CRUD的操作。

在使用Spring Data操作MongoDB中:

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

例如:我们有一个实体Person,有一个实体EmailAddress。

?

1

2

3

4

5

6

7
@Document(collection = "test_person")

public class Person {

private String name;

@DBRef

private EmailAddress emailAddress;

... getter setter 方法

}

?

1

2

3

4

5

6

7
@Document(collection = "test_email")

public class EmailAddress {

@Id

private String id;

private String value;

... getter setter 方法

}

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

?

1

2

3

4

5

6

7

8

9
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的其他值。

?

1

2

3

4

5

6

7

8

9
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,然后重写这些方法,即可以实现。

代码

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20
/**

* 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));

}

}

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36
/**

* 级联控制的回调

* 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);

}

}

}

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33
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);

}

}

}

}

?

1

2

3

4
@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.FIELD)

public @interface CascadeSave {

}

?

1

2

3

4

5

6

7
@Configuration

public class MongoConfig {

@Bean

public CascadeControlMongoEventListener userCascadingMongoEventListener() {

return new CascadeControlMongoEventListener();

}

}

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

总结

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

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

原文链接:http://webfuse.cn/2017/11/10/Spring%20Data%20MongoDB中的自定义级联

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 Spring Data MongoDB中实现自定义级联的方法详解 https://www.kuaiidc.com/114198.html

相关文章

发表评论
暂无评论