javascript
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批注
- 子對象正在保存
映射要求
如您所見,為了使工作正常,您需要遵循一些規則:
- 父類的子級屬性必須使用@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團隊接受。
翻譯自: https://www.javacodegeeks.com/2013/11/spring-data-mongodb-cascade-save-on-dbref-objects.html
總結
以上是生活随笔為你收集整理的Spring Data MongoDB级联保存在DBRef对象上的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓手绘app哪个好用(安卓手绘)
- 下一篇: 亚马逊Simple Worklfow服务