Spring Data MongoDB中實(shí)現(xiàn)自定義級(jí)聯(lián)的方法詳解
前言
Spring Data MongoDB 項(xiàng)目提供與MongoDB文檔數(shù)據(jù)庫(kù)的集成,Spring與Hibernate集成時(shí),Spring提供了org.springframework.orm.hibernate3.HibernateTemplate實(shí)現(xiàn)了對(duì)數(shù)據(jù)的CRUD操作, Spring Data MongoDB提供了org.springframework.data.mongodb.core.MongoTemplate對(duì)MongoDB的CRUD的操作,包括對(duì)集成的對(duì)象映射文件和POJO之間的CRUD的操作。
在使用Spring Data操作MongoDB中:
- 在保存一個(gè)實(shí)體的時(shí)候,如果被@DBRef標(biāo)識(shí)的類只傳入Id,保存后返回的結(jié)果并沒有全部的引用類內(nèi)容,只有Id。
- 保存實(shí)體,不能保存引用實(shí)體。
例如:我們有一個(gè)實(shí)體Person,有一個(gè)實(shí)體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 方法
}
當(dāng)我們調(diào)用保存方法的時(shí)候:
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,然后重寫這些方法,即可以實(shí)現(xiàn)。
代碼
/**
* MongoDB級(jí)聯(lián)控制
* 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));
}
}
/**
* 級(jí)聯(lián)控制的回調(diào)
* 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);
}
}
}
/**
* 級(jí)聯(lián)查詢
*
* @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) { //只處理一個(gè)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);
}
}
}
/**
* 級(jí)聯(lián)保存
*
* @param field
* @throws IllegalAccessException
*/
private void doCascadeSave(Field field) throws IllegalAccessException {
if (field.isAnnotationPresent(CascadeSave.class)) { //如果有標(biāo)識(shí)@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();
}
}
以上是核心代碼。至此,我們就可以解決上述的問題了。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
參考:http://www.baeldung.com/cascading-with-dbref-and-lifecycle-events-in-spring-data-mongodb
相關(guān)文章
解讀Spring接口方法加@Transactional失效的原因
這篇文章主要介紹了Spring接口方法加@Transactional失效的原因解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
Java并發(fā)編程之CountDownLatch原理詳解
這篇文章主要介紹了Java并發(fā)編程之CountDownLatch原理詳解,CountDownLatch類中使用了一個(gè)繼承自AQS的共享鎖Sync對(duì)象,構(gòu)造CountDownLatch對(duì)象時(shí)會(huì)將傳入的線程數(shù)值設(shè)為AQS的state值,需要的朋友可以參考下2023-12-12
SpringMvc @RequestParam 使用推薦使用包裝類型代替包裝類型
這篇文章主要介紹了SpringMvc @RequestParam 使用推薦使用包裝類型代替包裝類型,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-02-02
基于Spring AMQP實(shí)現(xiàn)消息隊(duì)列的示例代碼
Spring AMQP作為Spring框架的一部分,是一套用于支持高級(jí)消息隊(duì)列協(xié)議(AMQP)的工具,AMQP是一種強(qiáng)大的消息協(xié)議,旨在支持可靠的消息傳遞,本文給大家介紹了如何基于Spring AMQP實(shí)現(xiàn)消息隊(duì)列,需要的朋友可以參考下2024-03-03
Struts2中圖片以base64方式上傳至數(shù)據(jù)庫(kù)
這篇文章主要介紹了Struts2中圖片以base64方式上傳至數(shù)據(jù)庫(kù)的實(shí)現(xiàn)代碼,代碼分為前臺(tái)和后臺(tái)兩段,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-09-09

