1. अवलोकन
यह ट्यूटोरियल स्प्रिंग डेटा MongoDB की कुछ मुख्य विशेषताओं का पता लगाना जारी रखेगा - @DBRef एनोटेशन और जीवन-चक्र की घटनाएं।
2. @DBRef
मैपिंग फ्रेमवर्क अभिभावक-बाल संबंधों को संग्रहीत करने का समर्थन नहीं करता है और अन्य दस्तावेजों के भीतर एम्बेडेड दस्तावेज। हालांकि हम क्या कर सकते हैं - हम उन्हें अलग से स्टोर कर सकते हैं और DBRef . का उपयोग कर सकते हैं दस्तावेज़ों को संदर्भित करने के लिए।
जब ऑब्जेक्ट को MongoDB से लोड किया जाता है, तो उन संदर्भों को उत्सुकता से हल किया जाएगा, और हम एक मैप किए गए ऑब्जेक्ट को वापस प्राप्त करेंगे जो वैसा ही दिखता है जैसे कि इसे हमारे मास्टर दस्तावेज़ में एम्बेड किया गया हो।
आइए कुछ कोड देखें:
@DBRef
private EmailAddress emailAddress;
ईमेल पता ऐसा दिखता है:
@Document
public class EmailAddress {
@Id
private String id;
private String value;
// standard getters and setters
}
ध्यान दें कि मैपिंग फ्रेमवर्क कैस्केडिंग ऑपरेशन को हैंडल नहीं करता . इसलिए – उदाहरण के लिए – यदि हम सहेजें . को ट्रिगर करते हैं माता-पिता पर, बच्चा स्वचालित रूप से सहेजा नहीं जाएगा - अगर हम इसे भी सहेजना चाहते हैं तो हमें बच्चे पर बचत को स्पष्ट रूप से ट्रिगर करना होगा।
यहीं पर जीवन चक्र की घटनाएं काम आती हैं ।
3. जीवनचक्र घटनाएँ
स्प्रिंग डेटा MongoDB कुछ बहुत ही उपयोगी जीवन चक्र घटनाओं को प्रकाशित करता है - जैसे कि onBeforeConvert, onBeforeSave, onAfterSave, onAfterLoad और आफ्टर-कन्वर्ट पर।
किसी एक घटना को रोकने के लिए, हमें AbstractMappingEventListener के उपवर्ग को पंजीकृत करने की आवश्यकता है और यहां विधियों में से एक को ओवरराइड करें। जब ईवेंट भेजा जाता है, तो हमारे श्रोता को बुलाया जाएगा और डोमेन ऑब्जेक्ट पास किया जाएगा।
3.1. मूल कैस्केड सहेजें
आइए उस उदाहरण को देखें जो हमारे पास पहले था – उपयोगकर्ता . को सहेजना ईमेल पते . के साथ . अब हम onBeforeConvert सुन सकते हैं घटना जिसे डोमेन ऑब्जेक्ट कनवर्टर में जाने से पहले बुलाया जाएगा:
public class UserCascadeSaveMongoEventListener extends AbstractMongoEventListener<Object> {
@Autowired
private MongoOperations mongoOperations;
@Override
public void onBeforeConvert(BeforeConvertEvent<Object> event) {
Object source = event.getSource();
if ((source instanceof User) && (((User) source).getEmailAddress() != null)) {
mongoOperations.save(((User) source).getEmailAddress());
}
}
}
अब हमें केवल श्रोता को MongoConfig . में पंजीकृत करने की आवश्यकता है :
@Bean
public UserCascadeSaveMongoEventListener userCascadingMongoEventListener() {
return new UserCascadeSaveMongoEventListener();
}
या एक्सएमएल के रूप में:
<bean class="org.baeldung.event.UserCascadeSaveMongoEventListener" />
और हमारे पास कैस्केडिंग सिमेंटिक सब कुछ किया गया है - यद्यपि केवल उपयोगकर्ता के लिए।
3.2. एक सामान्य कैस्केड कार्यान्वयन
आइए अब कैस्केड कार्यक्षमता को सामान्य बनाकर पिछले समाधान में सुधार करें। आइए एक कस्टम एनोटेशन को परिभाषित करके शुरू करें:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CascadeSave {
//
}
आइए अब अपने कस्टम श्रोता पर काम करें इन क्षेत्रों को सामान्य रूप से संभालने के लिए और किसी विशेष इकाई को कास्ट करने की आवश्यकता नहीं है:
public class CascadeSaveMongoEventListener extends AbstractMongoEventListener<Object> {
@Autowired
private MongoOperations mongoOperations;
@Override
public void onBeforeConvert(BeforeConvertEvent<Object> event) {
Object source = event.getSource();
ReflectionUtils.doWithFields(source.getClass(),
new CascadeCallback(source, mongoOperations));
}
}
इसलिए हम स्प्रिंग से रिफ्लेक्शन यूटिलिटी का उपयोग कर रहे हैं, और हम उन सभी क्षेत्रों पर अपना कॉलबैक चला रहे हैं जो हमारे मानदंडों को पूरा करते हैं:
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
ReflectionUtils.makeAccessible(field);
if (field.isAnnotationPresent(DBRef.class) &&
field.isAnnotationPresent(CascadeSave.class)) {
Object fieldValue = field.get(getSource());
if (fieldValue != null) {
FieldCallback callback = new FieldCallback();
ReflectionUtils.doWithFields(fieldValue.getClass(), callback);
getMongoOperations().save(fieldValue);
}
}
}
जैसा कि आप देख सकते हैं, हम उन क्षेत्रों की तलाश कर रहे हैं जिनमें DBRef . दोनों हों एनोटेशन के साथ-साथ CascadeSave . एक बार जब हमें ये फ़ील्ड मिल जाते हैं, तो हम चाइल्ड इकाई को सहेज लेते हैं।
आइए देखें फ़ील्ड कॉलबैक कक्षा जिसका उपयोग हम यह जांचने के लिए कर रहे हैं कि बच्चे के पास @Id . है या नहीं एनोटेशन:
public class FieldCallback 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
private EmailAddress emailAddress;
3.3. कैस्केड टेस्ट
आइए अब एक परिदृश्य पर एक नजर डालते हैं - हम एक उपयोगकर्ता . को सहेजते हैं ईमेल पते . के साथ , और सेव ऑपरेशन स्वचालित रूप से इस एम्बेडेड इकाई में कैस्केड करता है:
User user = new User();
user.setName("Brendan");
EmailAddress emailAddress = new EmailAddress();
emailAddress.setValue("[email protected]");
user.setEmailAddress(emailAddress);
mongoTemplate.insert(user);
आइए हमारे डेटाबेस की जाँच करें:
{
"_id" : ObjectId("55cee9cc0badb9271768c8b9"),
"name" : "Brendan",
"age" : null,
"email" : {
"value" : "[email protected]"
}
}