डीडीडी शैली एंटिटी फ्रेमवर्क कोर के साथ संस्थाओं

यह आलेख उन वर्गों के लिए डोमेन-चालित डिज़ाइन (DDD) सिद्धांतों को कैसे लागू करें, जो डेटाबेस के लिए एंटिटी फ्रेमवर्क कोर (EF Core) मैप करता है, और यह उपयोगी क्यों हो सकता है।

TLDR


डीडीडी दृष्टिकोण के कई फायदे हैं, लेकिन मुख्य बात यह है कि डीडीडी इकाई वर्ग के अंदर बनाने / संशोधित करने के कोड को स्थानांतरित करता है। यह एक डेवलपर की गलतफहमी / संभावना को कम करता है / वर्ग उदाहरणों को बनाने, शुरू करने और उपयोग करने के नियमों की व्याख्या करता है।

  1. एरिक इवांस की पुस्तक और उनके भाषणों में इस विषय पर अधिक जानकारी नहीं है:
  2. लगातार वस्तुओं (कक्षाएं) प्राप्त करने और उनके जीवन चक्र के प्रबंधन के लिए ग्राहक को एक सरल मॉडल प्रदान करें।
  3. आपकी इकाई कक्षाओं को स्पष्ट रूप से बताना चाहिए कि क्या उन्हें बदला जा सकता है, कैसे, और किन नियमों से।
  4. DDD में एक समुच्चय की अवधारणा है। एग्रीगेट संबंधित संस्थाओं का एक पेड़ है। डीडीडी के नियमों के अनुसार, समुच्चय के साथ काम "एकत्रीकरण जड़" (पेड़ के मूल सार) के माध्यम से किया जाना चाहिए।

एरिक अपने भाषणों में रिपॉजिटरी का उल्लेख करता है। मैं EF Core के साथ एक रिपॉजिटरी को लागू करने की अनुशंसा नहीं करता, क्योंकि EF पहले से ही रिपॉजिटरी और कार्य पैटर्न की इकाई को लागू करता है। मैं आपको इसके बारे में एक अलग लेख में बताऊंगा, " क्या यह ईएफ कोर के साथ भंडार का उपयोग करने के लायक है ?"

DDD- शैली इकाइयाँ


मैं डीडीडी शैली में इकाई कोड दिखा कर शुरू करूँगा और फिर इसकी तुलना ईएफ कोर के साथ आमतौर पर कैसे बनाई जाएगी। पुस्तक भंडार (अमेज़ॅन का एक बहुत ही सरल संस्करण)। ”डेटाबेस संरचना नीचे की छवि में दिखाई गई है।

छवि

पहले चार टेबल पुस्तकों के बारे में सब कुछ दर्शाते हैं: किताबें खुद, उनके लेखक, समीक्षाएं। नीचे दिए गए दो टेबल व्यापार तर्क कोड में उपयोग किए जाते हैं। इस विषय को एक अलग लेख में विस्तार से वर्णित किया गया है।
इस लेख के सभी कोड को GitHub पर GenericBizRunner रिपॉजिटरी में अपलोड किया गया है । GenericBizRunner लाइब्रेरी कोड के अलावा, ASP.NET कोर एप्लिकेशन का एक और उदाहरण है, जो व्यापार तर्क के साथ काम करने के लिए GenericBizRunner का उपयोग करता है। इसके बारे में अधिक लेख " व्यापार तर्क और एंटिटी फ्रेमवर्क कोर के साथ काम करने के लिए लाइब्रेरी " में लिखा गया है।
और यहाँ डेटाबेस संरचना के अनुरूप इकाई कोड है।

public class Book { public const int PromotionalTextLength = 200; public int BookId { get; private set; } //… all other properties have a private set //These are the DDD aggregate propties: Reviews and AuthorLinks public IEnumerable<Review> Reviews => _reviews?.ToList(); public IEnumerable<BookAuthor> AuthorsLink => _authorsLink?.ToList(); //private, parameterless constructor used by EF Core private Book() { } //public constructor available to developer to create a new book public Book(string title, string description, DateTime publishedOn, string publisher, decimal price, string imageUrl, ICollection<Author> authors) { //code left out } //now the methods to update the book's properties public void UpdatePublishedOn(DateTime newDate)… public IGenericErrorHandler AddPromotion(decimal newPrice, string promotionalText)… public void RemovePromotion()… //now the methods to update the book's aggregates public void AddReview(int numStars, string comment, string voterName, DbContext context)… public void RemoveReview(Review review)… } 

क्या देखना है:

  1. पंक्ति 5: निजी घोषित सभी इकाई संपत्तियों तक पहुँच स्थापित करें। इसका अर्थ है कि इस लेख में बाद में वर्णित सार्वजनिक तरीकों का उपयोग करके या तो निर्माणकर्ता का उपयोग करके डेटा को संशोधित किया जा सकता है।
  2. लाइन्स 9 और 10. संबंधित संग्रह (डीडीडी से समान समुच्चय) IEnumerable <T> के लिए सार्वजनिक पहुँच प्रदान करते हैं, ICollection <T> नहीं। इसका मतलब है कि आप सीधे संग्रह से आइटम नहीं जोड़ सकते हैं या हटा नहीं सकते हैं। आपको बुक क्लास से विशेष विधियों का उपयोग करना होगा।
  3. लाइन 13. ईएफ कोर को एक पैरामीटर रहित निर्माता की आवश्यकता होती है, लेकिन इसमें निजी पहुंच हो सकती है। इसका मतलब यह है कि अन्य एप्लिकेशन कोड आरंभिककरण को दरकिनार नहीं कर पाएंगे और एक पैरामीटर रहित रचनाकार का उपयोग करके कक्षाओं का उदाहरण बना सकते हैं (एक अनुवादक की टिप्पणी। बेशक आप केवल प्रतिबिंब का उपयोग करके इकाइयां बनाते हैं)
  4. लाइन्स 16-20: जिस तरह से आप बुक क्लास का एक उदाहरण बना सकते हैं वह है पब्लिक कंस्ट्रक्टर का उपयोग करना। इस निर्माता में ऑब्जेक्ट को इनिशियलाइज़ करने के लिए सभी आवश्यक जानकारी है। इस प्रकार, ऑब्जेक्ट एक वैध स्थिति में होने की गारंटी है।
  5. लाइनें 23-25: इन पंक्तियों में किसी पुस्तक की स्थिति को बदलने के तरीके हैं।
  6. लाइनें 28-29: ये विधियाँ आपको संबंधित संस्थाओं (समुच्चय) को बदलने देती हैं

23-39 लाइनों पर तरीके, मैं "पहुंच प्रदान करने वाले तरीकों" को कॉल करना जारी रखूंगा। ये विधियाँ एक इकाई के भीतर गुणों और संबंधों को बदलने का एकमात्र तरीका हैं। लब्बोलुआब यह है कि बुक क्लास "बंद" है। यह एक विशेष निर्माता के माध्यम से बनाया गया है और केवल उपयुक्त नामों के साथ विशेष तरीकों के माध्यम से आंशिक रूप से संशोधित किया जा सकता है। यह दृष्टिकोण ईएफ कोर में संस्थाओं को बनाने / संशोधित करने के लिए मानक दृष्टिकोण के साथ एक तीव्र विपरीत बनाता है, जिसमें सभी संस्थाओं में एक खाली डिफ़ॉल्ट निर्माता होता है और सभी संपत्तियों को सार्वजनिक घोषित किया जाता है। अगला सवाल यह है कि पहला दृष्टिकोण बेहतर क्यों है?

इकाई निर्माण तुलना


आइए हम json से कई पुस्तकों के डेटा प्राप्त करने और उनके आधार पर बुक कक्षाओं के उदाहरण बनाने के लिए कोड की तुलना करें।

एक। मानक दृष्टिकोण


 var price = (decimal) (bookInfoJson.saleInfoListPriceAmount ?? DefaultBookPrice) var book = new Book { Title = bookInfoJson.title, Description = bookInfoJson.description, PublishedOn = DecodePubishDate(bookInfoJson.publishedDate), Publisher = bookInfoJson.publisher, OrgPrice = price, ActualPrice = price, ImageUrl = bookInfoJson.imageLinksThumbnail }; byte i = 0; book.AuthorsLink = new List<BookAuthor>(); foreach (var author in bookInfoJson.authors) { book.AuthorsLink.Add(new BookAuthor { Book = book, Author = authorDict[author], Order = i++ }); } 

ख। डीडीडी शैली


 var authors = bookInfoJson.authors.Select(x => authorDict[x]).ToList(); var book = new Book(bookInfoJson.title, bookInfoJson.description, DecodePubishDate(bookInfoJson.publishedDate), bookInfoJson.publisher, ((decimal?)bookInfoJson.saleInfoListPriceAmount) ?? DefaultBookPrice, bookInfoJson.imageLinksThumbnail, authors); 

बुक क्लास कंस्ट्रक्टर कोड

 public Book(string title, string description, DateTime publishedOn, string publisher, decimal price, string imageUrl, ICollection<Author> authors) { if (string.IsNullOrWhiteSpace(title)) throw new ArgumentNullException(nameof(title)); Title = title; Description = description; PublishedOn = publishedOn; Publisher = publisher; ActualPrice = price; OrgPrice = price; ImageUrl = imageUrl; _reviews = new HashSet<Review>(); if (authors == null || !authors.Any()) throw new ArgumentException( "You must have at least one Author for a book", nameof(authors)); byte order = 0; _authorsLink = new HashSet<BookAuthor>( authors.Select(a => new BookAuthor(this, a, order++))); } 

क्या देखना है:

  1. लाइनें 1-2: कंस्ट्रक्टर आपको उचित आरंभीकरण के लिए आवश्यक सभी डेटा पास करने के लिए मजबूर करता है।
  2. लाइन्स 5, 6 और 17-9: कोड में व्यावसायिक नियमों के लिए कई जाँच शामिल हैं। इस विशेष मामले में, नियमों का उल्लंघन कोड में एक त्रुटि माना जाता है, इसलिए, उल्लंघन के मामले में, एक अपवाद फेंक दिया जाएगा। यदि उपयोगकर्ता इन त्रुटियों को ठीक कर सकता है, तो शायद मैं स्टेटिक फैक्ट्री का उपयोग करूंगा जो स्टेटस <T> लौटाता है (टिप्पणी अनुवादक। मैं विकल्प <T> या परिणाम <T> का उपयोग करता हूं, एक अधिक सामान्य नाम के रूप में)। स्थिति एक प्रकार है जो त्रुटियों की एक सूची देता है।
  3. लाइनें 21-23: बुकअथोर बाइंडिंग को कंस्ट्रक्टर में बनाया गया है। BookAuthor कंस्ट्रक्टर को आंतरिक पहुंच स्तर के साथ घोषित किया जा सकता है। इस तरह हम DAL के बाहर संबंधों के निर्माण को रोक सकते हैं।

जैसा कि आपने देखा होगा, एक इकाई बनाने के लिए कोड की मात्रा दोनों मामलों में लगभग समान है। तो डीडीडी शैली बेहतर क्यों है? उस में DDD शैली बेहतर है:

  1. पहुंच को नियंत्रित करता है। संपत्ति के आकस्मिक परिवर्तन को बाहर रखा गया है। कोई भी परिवर्तन संबंधित नाम के साथ निर्माता या सार्वजनिक विधि के माध्यम से होता है। जाहिर है कि क्या हो रहा है।
  2. DRY के अनुरूप (स्वयं को दोहराएं नहीं)। आपको कई स्थानों पर बुक इंस्टेंसेस बनाने की आवश्यकता हो सकती है। असाइनमेंट कोड कंस्ट्रक्टर में है और आपको इसे कई जगहों पर दोहराना नहीं है।
  3. जटिलता को छिपाता है। बुक क्लास में दो गुण हैं: एक्चुअलप्राइस और ऑर्गप्राइस। नई पुस्तक बनाते समय ये दोनों मूल्य समान होने चाहिए। एक मानक दृष्टिकोण में, प्रत्येक डेवलपर को इसके बारे में पता होना चाहिए। DDD दृष्टिकोण में, बुक क्लास डेवलपर के बारे में जानने के लिए यह पर्याप्त है। बाकी इस नियम के बारे में जानेंगे क्योंकि यह स्पष्ट रूप से कंस्ट्रक्टर में लिखा गया है।
  4. समग्र सृजन को छिपाता है। मानक दृष्टिकोण में, डेवलपर को मैन्युअल रूप से BookAuthor का एक उदाहरण बनाना होगा। डीडीडी शैली में, यह जटिलता कॉलिंग कोड के लिए एनकैप्सुलेटेड है।
  5. प्रॉपर्टी में निजी लिखने की सुविधा है
  6. डीडीडी का उपयोग करने का एक कारण इकाई को बंद करना है, अर्थात। सीधे गुण बदलने की क्षमता न दें। आइए डीडीडी के साथ और उसके बिना परिवर्तन ऑपरेशन की तुलना करें।

संपत्ति बदलें तुलना


एरिक इवांस डीडीडी-शैली संस्थाओं के मुख्य लाभों में से एक को निम्नलिखित कहते हैं: "वे ऑब्जेक्ट एक्सेस के बारे में डिजाइन निर्णय लेते हैं"।
लगभग। दुभाषिया। मूल वाक्यांश रूसी में अनुवाद करना मुश्किल है। इस मामले में, डिजाइन निर्णय ऐसे निर्णय होते हैं जो सॉफ़्टवेयर को काम करना चाहिए। इसका मतलब है कि निर्णयों पर चर्चा की गई और पुष्टि की गई। कंस्ट्रक्टर्स के साथ कोड जो सही नाम के साथ संस्थाओं और विधियों को सही ढंग से आरंभ करते हैं जो ऑपरेशन के अर्थ को दर्शाते हैं स्पष्ट रूप से डेवलपर को बताते हैं कि कुछ मूल्यों के असाइनमेंट इरादे से किए गए थे, और गलती से नहीं, और किसी अन्य डेवलपर या कार्यान्वयन विवरण का एक हिस्सा नहीं है।
मैं इस वाक्यांश को इस प्रकार समझता हूं।

  1. यह स्पष्ट करें कि किसी इकाई के भीतर डेटा को कैसे संशोधित किया जाए और किन डेटा को एक साथ बदलना चाहिए।
  2. यह स्पष्ट करें कि आपको इकाई में कुछ डेटा को संशोधित नहीं करना चाहिए।
आइए दोनों दृष्टिकोणों की तुलना करें। पहला उदाहरण सरल है, और दूसरा अधिक जटिल है।

1. प्रकाशन तिथि में परिवर्तन


मान लीजिए हम पहले किसी पुस्तक के मसौदे के साथ काम करना चाहते हैं और उसके बाद ही उसे प्रकाशित करते हैं। मसौदा लिखने के समय, एक अनुमानित प्रकाशन तिथि निर्धारित की जाती है, जिसे संपादन प्रक्रिया के दौरान बदलने की संभावना है। प्रकाशन तिथि को संग्रहीत करने के लिए, हम PublishedOn संपत्ति का उपयोग करेंगे।

एक। सार्वजनिक संपत्तियों के साथ इकाई


 var book = context.Find<Book>(dto.BookId); book.PublishedOn = dto.PublishedOn; context.SaveChanges(); 

ख। डीडीडी शैली इकाई


डीडीडी शैली में, संपत्ति के सेटर को निजी घोषित किया जाता है, इसलिए हम एक विशेष पहुंच विधि का उपयोग करेंगे।

 var book = context.Find<Book>(dto.BookId); book.UpdatePublishedOn( dto.PublishedOn); context.SaveChanges(); 

ये दोनों मामले लगभग एक जैसे हैं। डीडीडी संस्करण थोड़ा लंबा है। लेकिन अभी भी एक अंतर है। डीडीडी शैली में, आप यह सुनिश्चित करने के लिए जानते हैं कि प्रकाशन की तारीख को बदला जा सकता है क्योंकि एक स्पष्ट नाम के साथ एक विधि है। आप यह भी जानते हैं कि आप प्रकाशक को नहीं बदल सकते क्योंकि प्रकाशक की संपत्ति को बदलने की उपयुक्त विधि नहीं है। यह जानकारी पुस्तक वर्ग के साथ काम करने वाले किसी भी प्रोग्रामर के लिए उपयोगी होगी।

2. पुस्तक के लिए छूट का प्रबंधन करें


एक और आवश्यकता यह है कि हमें छूट का प्रबंधन करने में सक्षम होना चाहिए। छूट में एक नई कीमत और एक टिप्पणी शामिल है, उदाहरण के लिए, "इस सप्ताह के अंत से पहले 50%!"

इस नियम का कार्यान्वयन सरल है, लेकिन बहुत स्पष्ट नहीं है।

  1. OrgPrice संपत्ति बिना छूट के मूल्य है।
  2. एक्चुअलप्राइस - वर्तमान मूल्य जिस पर पुस्तक बेची जा रही है। यदि छूट मान्य है, तो वर्तमान मूल्य छूट के आकार से OrgPrice से अलग होगा। यदि नहीं, तो गुणों का मूल्य बराबर होगा।
  3. यदि छूट वर्तमान में लागू नहीं होती है, तो प्रमोशन टेक्स्ट संपत्ति में छूट पाठ होना चाहिए।

नियम उन लोगों के लिए बहुत स्पष्ट हैं जिन्होंने उन्हें लागू किया। हालाँकि, एक अन्य डेवलपर के लिए, छूट जोड़ने के लिए UI विकसित करना कहते हैं। इकाई वर्ग में AddPromotion और RemovePromotion विधियों को जोड़ना कार्यान्वयन विवरण को छुपाता है। अब एक और डेवलपर के पास संबंधित नामों के साथ सार्वजनिक तरीके हैं। विधियों का उपयोग करने का शब्दार्थ स्पष्ट है।

AddPromotion और RemovePromotion विधियों के कार्यान्वयन पर एक नज़र डालें।

 public IGenericErrorHandler AddPromotion(decimal newPrice, string promotionalText) { var status = new GenericErrorHandler(); if (string.IsNullOrWhiteSpace(promotionalText)) { status.AddError( "You must provide some text to go with the promotion.", nameof(PromotionalText)); return status; } ActualPrice = newPrice; PromotionalText = promotionalText; return status; } 

क्या देखना है:

  1. लाइन्स 4-10: प्रोमोशनलटेक्स्ट टिप्पणी जोड़ना आवश्यक है। विधि जाँचती है कि पाठ खाली नहीं है। क्योंकि उपयोगकर्ता इस त्रुटि को ठीक कर सकता है। विधि सुधार के लिए त्रुटियों की एक सूची देता है।
  2. पंक्तियाँ 12, 13: विधि उस गुण के मानों को निर्धारित करती है जो डेवलपर ने चुना है। AddPromotion विधि के उपयोगकर्ता को उन्हें जानना नहीं है। छूट जोड़ने के लिए, बस लिखें:

 var book = context.Find<Book>(dto.BookId); var status = book.AddPromotion(newPrice, promotionText); if (!status.HasErrors) context.SaveChanges(); return status; 

RemovePromotion विधि बहुत सरल है: इसमें त्रुटि हैंडलिंग शामिल नहीं है। इसलिए, वापसी मूल्य सिर्फ शून्य है।

 public void RemovePromotion() { ActualPrice = OrgPrice; PromotionalText = null; } 

ये दो उदाहरण एक दूसरे से बहुत अलग हैं। पहले उदाहरण में, प्रकाशित करें प्रॉपर्टी को बदलना इतना सरल है कि मानक कार्यान्वयन ठीक है। दूसरे उदाहरण में, कार्यान्वयन विवरण उन लोगों के लिए स्पष्ट नहीं है जिन्होंने पुस्तक वर्ग के साथ काम नहीं किया है। दूसरे मामले में, विशेष पहुंच विधियों के साथ डीडीडी-शैली कार्यान्वयन विवरण को छुपाती है और अन्य डेवलपर्स के जीवन को आसान बनाती है। इसके अलावा, दूसरे उदाहरण में, कोड में व्यावसायिक तर्क हैं। जबकि तर्क की मात्रा छोटी है, हम इसे सीधे एक्सेस विधियों में संग्रहीत कर सकते हैं और यदि सिस्टम सही तरीके से उपयोग नहीं किया गया है, तो त्रुटियों की एक सूची वापस कर सकते हैं।

3. समग्र के साथ काम करें - संपत्ति संग्रह समीक्षा


DDD केवल रूट के माध्यम से इकाई के साथ काम करने की पेशकश करता है। हमारे मामले में, समीक्षा संपत्ति समस्याएं पैदा करती है। यहां तक ​​कि अगर सेटर को निजी घोषित किया जाता है, तब भी डेवलपर ऐड और रिमूव मेथड का इस्तेमाल करके ऑब्जेक्ट्स को जोड़ या हटा सकता है, या पूरे कलेक्शन को क्लियर करने के लिए क्लियर मेथड को भी कॉल कर सकता है। नए EF Core फ़ीचर, बैकिंग फ़ील्ड, यहाँ हमारी मदद करेंगे।

बैकिंग फ़ील्ड डेवलपर को वास्तविक संग्रह को एन्क्रिप्ट करने और IEnumerable <T> इंटरफ़ेस लिंक तक सार्वजनिक पहुंच प्रदान करने की अनुमति देता है। IEnumerable <T> इंटरफ़ेस जोड़ने, हटाने या स्पष्ट तरीके प्रदान नहीं करता है। नीचे दिए गए कोड में बैकिंग फ़ील्ड का उपयोग करने का एक उदाहरण है।

 public class Book { private HashSet<Review> _reviews; public IEnumerable<Review> Reviews => _reviews?.ToList(); //… rest of code not shown } 

इस काम के लिए, आपको EF Core को यह बताना होगा कि डेटाबेस से पढ़ते समय, आपको एक निजी क्षेत्र में लिखना होगा, सार्वजनिक संपत्ति नहीं। कॉन्फ़िगरेशन कोड नीचे दिखाया गया है।

 protected override void OnModelCreating (ModelBuilder modelBuilder) { modelBuilder.Entity<Book>() .FindNavigation(nameof(Book.Reviews)) .SetPropertyAccessMode(PropertyAccessMode.Field); //… other non-review configurations left out } 

समीक्षाओं के साथ काम करने के लिए, मैंने दो विधियाँ जोड़ी: पुस्तक कक्षा में AddReview और RemoveReview। AddReview विधि अधिक रोचक है। यहाँ उसका कोड है:

 public void AddReview(int numStars, string comment, string voterName, DbContext context = null) { if (_reviews != null) { _reviews.Add(new Review(numStars, comment, voterName)); } else if (context == null) { throw new ArgumentNullException(nameof(context), "You must provide a context if the Reviews collection isn't valid."); } else if (context.Entry(this).IsKeySet) { context.Add(new Review(numStars, comment, voterName, BookId)); } else { throw new InvalidOperationException("Could not add a new review."); } } 

क्या देखना है:

  1. लाइन्स 4-7: मैं जानबूझकर _reviews फ़ील्ड को एक निजी पैरामीटर रहित कंस्ट्रक्टर में इनिशियलाइज़ नहीं करता हूँ, जो EF Core डेटाबेस से लोडिंग इकाइयाँ इस्तेमाल करते समय करता है। यह मेरे कोड को यह निर्धारित करने की अनुमति देता है कि क्या संग्रह .Include विधि (p => p.Reviews) का उपयोग करके लोड किया गया था। सार्वजनिक कंस्ट्रक्टर में, मैं फ़ील्ड को इनिशियलाइज़ करता हूं, इसलिए एनआरई तब नहीं होगा जब निर्मित इकाई के साथ काम कर रहा हो।
  2. लाइनें 8-12: यदि समीक्षा संग्रह लोड नहीं किया गया था, तो कोड को आरंभ करने के लिए DbContext का उपयोग करना चाहिए।
  3. लाइनें 13-16: यदि पुस्तक सफलतापूर्वक बनाई गई थी और इसमें एक आईडी शामिल है, तो मैं एक समीक्षा जोड़ने के लिए दूसरी तकनीक का उपयोग करता हूं: मैं केवल समीक्षा वर्ग के एक उदाहरण में विदेशी कुंजी स्थापित करता हूं और इसे डेटाबेस में लिखता हूं। यह मेरी पुस्तक के अनुभाग 3.4.5 में अधिक विस्तार से वर्णित है।
  4. पंक्ति 19: यदि हम यहां हैं, तो कोड के तर्क के साथ कुछ समस्या है। तो मैं एक अपवाद फेंक देता हूं।

मैंने अपने सभी एक्सेस के तरीकों को उलट मामलों के लिए डिज़ाइन किया है जहां केवल रूट इकाई भरी हुई है। यूनिट को कैसे अपडेट किया जाए यह विधियों के विवेक पर है। आपको अतिरिक्त संस्थाओं को लोड करने की आवश्यकता हो सकती है।

निष्कर्ष


ईडी कोर के साथ डीडीडी शैली में इकाइयां बनाने के लिए, आपको निम्नलिखित नियमों का पालन करना होगा:

  1. सार्वजनिक निर्माणकर्ताओं को सही ढंग से प्रारंभिक वर्ग उदाहरण बनाने के लिए बनाएँ। यदि निर्माण प्रक्रिया के दौरान त्रुटियां हो सकती हैं, जो उपयोगकर्ता को सही कर सकता है, तो सार्वजनिक निर्माणकर्ता का उपयोग न करके ऑब्जेक्ट बनाएं, लेकिन स्थिति <T> लौटाते हुए फ़ैक्टरी विधि का उपयोग करते हुए, जहाँ T किस प्रकार की इकाई बनाई जा रही है
  2. सभी गुण संपत्ति बसने वाले हैं। यानी सभी गुण केवल कक्षा के बाहर ही पढ़े जाते हैं।
  3. संग्रह नेविगेशन गुणों के लिए, बैकिंग फ़ील्ड घोषित करें, और सार्वजनिक संपत्ति प्रकार IEnumerable <T> घोषित करें। यह अन्य डेवलपर्स को अनियंत्रित रूप से संग्रह बदलने से रोकेगा।
  4. सार्वजनिक बस्तियों के बजाय, सभी अनुमत ऑब्जेक्ट परिवर्तन कार्यों के लिए सार्वजनिक विधियाँ बनाएँ। यदि ऑपरेशन उपयोगकर्ता को ठीक कर सकता है या स्थिति <T> यदि वे कर सकते हैं तो एक त्रुटि के साथ विफल हो जाने पर इन विधियों को शून्य वापस करना चाहिए।
  5. इकाई दायित्व का दायरा मायने रखता है। मुझे लगता है कि संस्थाओं को केवल खुद को और अन्य वर्गों को समूह के अंदर बदलने के लिए सीमित करना सबसे अच्छा है, लेकिन बाहर नहीं। संस्थाओं की स्थिति के निर्माण और परिवर्तन की शुद्धता की जांच करने के लिए वैधता नियम सीमित होना चाहिए। यानी मैं व्यापार नियमों की जाँच नहीं करता जैसे स्टॉक बैलेंस। इसके लिए एक विशेष व्यावसायिक तर्क कोड है।
  6. राज्य बदलते तरीकों को यह मान लेना चाहिए कि केवल एकत्रीकरण जड़ भरी हुई है। यदि किसी विधि को अन्य डेटा लोड करने की आवश्यकता है, तो उसे स्वयं ही इसका ध्यान रखना चाहिए।
  7. राज्य बदलते तरीकों को यह मान लेना चाहिए कि केवल एकत्रीकरण जड़ भरी हुई है। यदि किसी विधि को अन्य डेटा लोड करने की आवश्यकता है, तो उसे स्वयं ही इसका ध्यान रखना चाहिए। यह दृष्टिकोण अन्य डेवलपर्स द्वारा संस्थाओं के उपयोग को सरल करता है।

ईडी कोर के साथ काम करते समय डीडीडी संस्थाओं के पेशेवरों और विपक्ष


मुझे किसी भी पैटर्न या वास्तुकला के लिए महत्वपूर्ण दृष्टिकोण पसंद है। यहाँ मैं DDD संस्थाओं का उपयोग करने के बारे में सोचता हूँ।

आकर्षण आते हैं


  1. राज्य को बदलने के लिए विशेष तरीकों का उपयोग करना एक क्लीनर दृष्टिकोण है। यह निश्चित रूप से एक अच्छा समाधान है, सिर्फ इसलिए कि ठीक से नामित तरीके कोड इरादों को बहुत बेहतर बताते हैं और यह स्पष्ट करते हैं कि क्या बदला जा सकता है और क्या नहीं। इसके अतिरिक्त, यदि उपयोगकर्ता उन्हें ठीक कर सकते हैं, तो विधियाँ त्रुटियों की एक सूची वापस कर सकती हैं।
  2. केवल रूट के माध्यम से समुच्चय बदलना भी अच्छी तरह से काम करता है
  3. पुस्तक और समीक्षा कक्षाओं के बीच एक-से-कई संबंधों का विवरण अब उपयोगकर्ता के लिए छिपा हुआ है। एनकैप्सुलेशन OOP का एक मूल सिद्धांत है।
  4. विशेष निर्माणकर्ताओं का उपयोग करने से आपको यह सुनिश्चित करने की अनुमति मिलती है कि इकाइयां बनाई गई हैं और सही ढंग से आरंभिक होने की गारंटी है।
  5. प्रारंभिक कोड को कंस्ट्रक्टर में ले जाने से यह संभावना कम हो जाती है कि डेवलपर सही ढंग से व्याख्या नहीं करता है कि वर्ग को कैसे आरम्भ किया जाना चाहिए।

विपक्ष


  1. मेरे दृष्टिकोण में EF कोर के कार्यान्वयन पर निर्भरताएं हैं।
  2. कुछ लोग इसे प्रतिरूप भी कहते हैं। समस्या यह है कि अब विषय मॉडल की इकाइयाँ डेटाबेस एक्सेस कोड पर निर्भर करती हैं। DDD के संदर्भ में, यह बुरा है। मुझे एहसास हुआ कि अगर मैंने ऐसा नहीं किया, तो मुझे यह जानने के लिए फोन करने वाले पर भरोसा करना होगा कि क्या लोड होना चाहिए। यह दृष्टिकोण चिंताओं के पृथक्करण के सिद्धांत को तोड़ता है।
  3. DDD आपको अधिक कोड लिखने के लिए मजबूर करता है।

क्या यह वास्तव में साधारण मामलों में इसके लायक है, जैसे किसी पुस्तक की प्रकाशन तिथि को अद्यतन करना?
जैसा कि आप देख सकते हैं, मुझे DDD दृष्टिकोण पसंद है। हालाँकि, मुझे इसे सही ढंग से तैयार करने में थोड़ा समय लगा, लेकिन फिलहाल इस दृष्टिकोण को सुलझा लिया गया है और मैं इसे उन परियोजनाओं में लागू कर रहा हूं जिन पर मैं काम कर रहा हूं। मैं पहले से ही छोटी परियोजनाओं में इस शैली का प्रयास करने में कामयाब रहा और संतुष्ट हूं, लेकिन सभी परियोजनाओं और विपक्ष को अभी तक पता नहीं चल पाया है कि मैं इसे बड़ी परियोजनाओं में उपयोग करता हूं।

इकाई मॉडल इकाई विधियों के तर्कों में EFCore- विशिष्ट कोड के उपयोग की अनुमति देने का मेरा निर्णय सरल नहीं था। मैंने इसे रोकने की कोशिश की, लेकिन अंत में मैं इस नतीजे पर पहुंचा कि कॉलिंग कोड में बहुत सारे नेविगेशन प्रॉपर्टी लोड करने थे। और अगर ऐसा नहीं किया जाता है, तो परिवर्तन बिना किसी त्रुटि के लागू नहीं किया जाएगा (विशेषकर एक-से-एक संबंध में)। यह मेरे लिए स्वीकार्य नहीं था, इसलिए मैंने कुछ तरीकों (लेकिन कंस्ट्रक्टर नहीं) के अंदर ईएफ कोर के उपयोग की अनुमति दी।

एक और बुरा पक्ष यह है कि DDD आपको CRUD संचालन के लिए काफी अधिक कोड लिखने के लिए मजबूर करता है। मुझे अभी भी यकीन नहीं है कि कैक्टस खाना जारी रखना है या सभी गुणों के लिए अलग-अलग तरीके लिखना है, या कुछ मामलों में यह इस तरह के कट्टरपंथी शुद्धतावाद से दूर जाने के लायक है। मुझे पता है कि बस एक गाड़ी और बोरिंग CRUD का एक छोटा ट्रक है, जो सीधे लिखना आसान है। केवल वास्तविक परियोजनाओं पर काम ही दिखाएगा जो बेहतर है।

अन्य डीडीडी पहलुओं को इस लेख में शामिल नहीं किया गया है


लेख बहुत लंबा हो गया है, इसलिए मैं यहां समाप्त करने जा रहा हूं। लेकिन, इसका मतलब यह है कि अभी भी बहुत सारी अघोषित सामग्री मौजूद है। मैंने पहले से ही कुछ के बारे में लिखा था, कुछ के बारे में मैं निकट भविष्य में लिखूंगा। यहाँ क्या छोड़ा गया है:

  1. व्यापार तर्क और DDD। मैं कई वर्षों से व्यापार तर्क कोड में DDD अवधारणाओं का उपयोग कर रहा हूं और, EF Core की नई विशेषताओं का उपयोग करते हुए, मुझे उम्मीद है कि मैं तर्क के कुछ को इकाई कोड में स्थानांतरित कर सकता हूं। "फ्रेमवर्क विथ द बिज़नेस लॉजिक आर्किटेक्चर ऑन अगेन फ्रेमवर्क (कोर और v6)" लेख पढ़ें
  2. DDD और रिपॉजिटरी पैटर्न। एरिक इवांस सार डेटा का उपयोग करने के लिए एक भंडार का उपयोग करने की सलाह देते हैं। , «» EF Core – . क्यों? - .
  3. DBContext' / (bounded contexts). DbContext'. , BookContext Book OrderContext, . , « » , . , .

इस लेख का सभी कोड GitHub पर GenericBizRunner रिपॉजिटरी में उपलब्ध हैइस रिपॉजिटरी में बुक क्लास को संशोधित करने के लिए विशेष एक्सेस विधियों के साथ एक उदाहरण ASP.NET कोर एप्लिकेशन है। आप रिपॉजिटरी को क्लोन कर सकते हैं और एप्लिकेशन को स्थानीय रूप से चला सकते हैं। यह एक डेटाबेस के रूप में इन-मेमोरी स्क्लाइट का उपयोग करता है, इसलिए इसे किसी भी बुनियादी ढांचे पर चलना चाहिए।

खुश विकास!

Source: https://habr.com/ru/post/hi432410/


All Articles