日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring Data MongoDB级联保存在DBRef对象上

發布時間:2023/12/3 javascript 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring Data MongoDB级联保存在DBRef对象上 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

默認情況下, Spring Data MongoDB不支持對帶有@DBRef注釋的引用對象的級聯操作,如引用所述 :

映射框架不處理級聯保存 。 如果更改了Person對象引用的Account對象,則必須單獨 保存 Account對象。 在Person對象上調用save 不會自動將Account對象保存在屬性帳戶中。

這很成問題,因為要實現保存子對象,您需要覆蓋父存儲庫中的save方法或創建其他“服務”? 這里介紹了類似的方法。

在本文中,我將向您展示如何使用AbstractMongoEventListener的通用實現針對所有文檔實現此目標。

@CascadeSave批注

由于我們無法通過添加級聯屬性來更改@DBRef批注,因此可以創建新的批注@CascadeSave,該批注將用于標記保存父對象時應保存哪些字段。

package pl.maciejwalkowiak.springdata.mongodb;import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.FIELD }) public @interface CascadeSave {}

CascadingMongoEventListener

下一部分是實現此批注的處理程序。 我們將使用強大的Spring Application Event機制 。 特別是,我們將擴展AbstractMongoEventListener以捕獲已保存的對象,然后再將其轉換為Mongo的DBObject 。

它是如何工作的? 調用對象MongoTemplate #save方法時,在實際保存對象之前,會將其從MongoDB api轉換為DBObject。 下面實現的CascadingMongoEventListener提供了在對象轉換之前捕獲對象的鉤子,并且:

  • 仔細檢查其所有字段,以檢查是否同時有@DBRef和@CascadeSave注釋的字段。
  • 找到字段時,它將檢查是否存在@Id批注
  • 子對象正在保存
package pl.maciejwalkowiak.springdata.mongodb;import org.bson.types.ObjectId; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.annotation.Id; import org.springframework.data.mapping.model.MappingException; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.mapping.DBRef; import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener; import org.springframework.stereotype.Component; import org.springframework.util.ReflectionUtils;import java.lang.reflect.Field;public class CascadingMongoEventListener extends AbstractMongoEventListener {@Autowiredprivate MongoOperations mongoOperations;@Overridepublic void onBeforeConvert(final Object source) {ReflectionUtils.doWithFields(source.getClass(), new ReflectionUtils.FieldCallback() {public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {ReflectionUtils.makeAccessible(field);if (field.isAnnotationPresent(DBRef.class) && field.isAnnotationPresent(CascadeSave.class)) {final Object fieldValue = field.get(source);DbRefFieldCallback callback = new DbRefFieldCallback();ReflectionUtils.doWithFields(fieldValue.getClass(), callback);if (!callback.isIdFound()) {throw new MappingException("Cannot perform cascade save on child object without id set");}mongoOperations.save(fieldValue);}}});}private static class DbRefFieldCallback implements ReflectionUtils.FieldCallback {private boolean idFound;public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {ReflectionUtils.makeAccessible(field);if (field.isAnnotationPresent(Id.class)) {idFound = true;}}public boolean isIdFound() {return idFound;}} }

映射要求

如您所見,為了使工作正常,您需要遵循一些規則:

  • 父類的子級屬性必須使用@DBRef和@CascadeSave進行映射
  • 子類需要具有以@Id注釋的屬性,如果應該自動生成該ID,則應按ObjectId的類型

用法

為了在項目中使用級聯保存,您只需要在Spring Context中注冊CascadingMongoEventListener:

<bean class="pl.maciejwalkowiak.springdata.mongodb.CascadingMongoEventListener" />

讓我們測試一下

為了顯示一個示例,我制作了兩個文檔類:

@Document public class User {@Idprivate ObjectId id;private String name;@DBRef@CascadeSaveprivate Address address;public User(String name) {this.name = name;}// ... getters, setters, equals hashcode }@Document public class Address {@Idprivate ObjectId id;private String city;public Address(String city) {this.city = city;}// ... getters, setters, equals hashcode }

在測試中,有一個創建了地址的用戶,然后保存了該用戶。 測試將僅涵蓋積極的情況,并且僅用于表明它確實有效( applcationContext-tests.xml僅包含默認的Spring Data MongoDB Bean和已注冊的CascadingMongoEventListener):

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:applcationContext-tests.xml"}) public class CascadingMongoEventListenerTest {@Autowiredprivate MongoOperations mongoOperations;/*** Clean collections before tests are executed*/@Beforepublic void cleanCollections() {mongoOperations.dropCollection(User.class);mongoOperations.dropCollection(Address.class);}@Testpublic void testCascadeSave() {// givenUser user = new User("John Smith");user.setAddress(new Address("London"));// whenmongoOperations.save(user);// thenList<User> users = mongoOperations.findAll(User.class);assertThat(users).hasSize(1).containsOnly(user);User savedUser = users.get(0);assertThat(savedUser.getAddress()).isNotNull().isEqualTo(user.getAddress());List<Address> addresses = mongoOperations.findAll(Address.class);assertThat(addresses).hasSize(1).containsOnly(user.getAddress());} }

我們也可以在Mongo控制臺中進行檢查:

> db.user.find() { "_id" : ObjectId("4f9d1bab1a8854250a5bf13e"), "_class" : "pl.maciejwalkowiak.springdata.mongodb.domain.User", "name" : "John Smith", "address" : { "$ref" : "address", "$id" : ObjectId("4f9d1ba41a8854250a5bf13d") } } > db.address.find() { "_id" : ObjectId("4f9d1ba41a8854250a5bf13d"), "_class" : "pl.maciejwalkowiak.springdata.mongodb.domain.Address", "city" : "London" }

摘要

通過這種簡單的解決方案,我們最終可以通過一個方法調用保存子對象,而無需為每個文檔類實現任何特殊的功能。

我相信,將來作為Spring Data MongoDB版本的一部分,我們會在級聯刪除中找到該功能。 這里介紹的解決方案有效,但:

  • 它需要使用其他注釋
  • 使用反射API遍歷字段,這不是最快的方法(但可以根據需要隨意實現緩存)

如果這可以是Spring Data MongoDB的一部分,而不是附加的注釋,則@DBRef可以具有附加的cascade屬性。 除了反射之外,我們可以將MongoMappingContext和MongoPersistentEntity一起使用。 我已經開始準備帶有這些更改的請求請求。 我們將看看它是否將被Spring Source團隊接受。

參考: Spring Data MongoDB級聯保存在我們的JCG合作伙伴 Maciej Walkowiak的“ 軟件開發之旅”博客上的DBRef對象上。

翻譯自: https://www.javacodegeeks.com/2013/11/spring-data-mongodb-cascade-save-on-dbref-objects.html

總結

以上是生活随笔為你收集整理的Spring Data MongoDB级联保存在DBRef对象上的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。