كيانات نمط DDD مع Entity Framework Core

تتناول هذه المقالة كيفية تطبيق مبادئ التصميم القائم على المجال (DDD) على الفئات التي يعينها Entity Framework Core (EF Core) إلى قاعدة البيانات ، ولماذا قد يكون ذلك مفيدًا.

TLDR


هناك العديد من المزايا لنهج DDD ، لكن الشيء الرئيسي هو أن DDD تنقل كود إنشاء / تعديل العمليات داخل فئة الكيان. هذا يقلل بشكل كبير من فرص سوء فهم المطور / تفسير قواعد إنشاء مثيلات الفصل وتهيئتها واستخدامها.

  1. لا يحتوي كتاب إريك إيفانز وخطبه على الكثير من المعلومات حول هذا الموضوع:
  2. زوّد العميل بنموذج بسيط للحصول على كائنات ثابتة (فئات) وإدارة دورة حياته.
  3. يجب أن تحدد فئات الكيانات الخاصة بك صراحة ما إذا كان يمكن تغييرها وكيف وكيف وبأي قواعد.
  4. في DDD هناك مفهوم الكلي. التجميع هو شجرة الكيانات ذات الصلة. وفقًا لقواعد DDD ، يجب تنفيذ العمل مع المجاميع من خلال "جذر التجميع" (جوهر جذر الشجرة).

يذكر إريك مستودعات في خطبه. لا أوصي بتنفيذ مستودع مع EF Core ، لأن EF يطبق بالفعل المستودع ووحدة أنماط العمل في حد ذاتها. سأخبركم المزيد حول هذا الموضوع في مقال منفصل ، " هل يستحق استخدام مستودع مع EF Core ؟"

كيانات نمط DDD


سأبدأ بإظهار رمز الكيان في نمط DDD ثم مقارنته بكيفية إنشاء الكيانات التي لها EF Core عادة (ملاحظة المترجم. يسمي المؤلف الكلمة "عادةً" نموذجًا مصابًا بفقر الدم). في هذا المثال ، سأستخدم قاعدة بيانات الإنترنت متجر الكتب (نسخة مبسطة جدًا من Amazon. "يظهر هيكل قاعدة البيانات في الصورة أدناه.

الصورة

تمثل الجداول الأربعة الأولى كل شيء عن الكتب: الكتب نفسها ، مؤلفوها ، المراجعات. يتم استخدام الجدولين أدناه في رمز منطق العمل. يوصف هذا الموضوع بالتفصيل في مقال منفصل.
تم تحميل جميع الشفرات الخاصة بهذه المقالة إلى مستودع GenericBizRunner على GitHub . بالإضافة إلى رمز مكتبة GenericBizRunner ، يوجد مثال آخر لتطبيق ASP.NET Core يستخدم GenericBizRunner للعمل مع منطق الأعمال. تم كتابة المزيد حول هذا الموضوع في مقالة " مكتبة للعمل مع منطق العمل و Entity Framework Core ."
وهنا هو رمز الكيان المقابلة لهيكل قاعدة البيانات.

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. المجموعات ذات الصلة (نفس المجاميع من DDD) وصولاً عامًا إلى IEnumerable <T> ، وليس ICollection <T>. هذا يعني أنه لا يمكنك إضافة أو إزالة عناصر من المجموعة مباشرة. سوف تضطر إلى استخدام أساليب متخصصة من فئة الكتاب.
  3. السطر 13. EF Core يتطلب مُنشئ بلا معلمات ، لكن يمكن أن يكون له وصول خاص. هذا يعني أن رمز التطبيق الآخر لن يكون قادرًا على تجاوز التهيئة وإنشاء مثيلات للفئات باستخدام مُنشئ غير معلمي (تعليق مترجم. ما لم تقم بالطبع بإنشاء كيانات تستخدم الانعكاس فقط)
  4. الأسطر 16-20: الطريقة الوحيدة التي يمكنك بها إنشاء مثيل لفئة الكتاب هي استخدام المنشئ العام. يحتوي هذا المنشئ على جميع المعلومات اللازمة لتهيئة الكائن. وبالتالي ، فإن الكائن مضمون في حالة صالحة.
  5. الأسطر 23-25: تحتوي هذه الأسطر على طرق لتغيير حالة كتاب.
  6. الأسطر 28-29: هذه الأساليب تتيح لك تغيير الكيانات ذات الصلة (المجاميع)

الأساليب على الأسطر 23-39 ، سأستمر في استدعاء "الأساليب التي توفر الوصول". هذه الطرق هي الطريقة الوحيدة لتغيير الخصائص والعلاقات داخل الكيان. خلاصة القول هي أن فئة الكتاب "مغلقة". يتم إنشاؤه من خلال مُنشئ خاص ولا يمكن تعديله جزئيًا إلا من خلال طرق خاصة بأسماء مناسبة. يخلق هذا النهج تباينًا حادًا مع النهج القياسي لإنشاء / تعديل الكيانات في EF Core ، حيث تحتوي جميع الكيانات على مُنشئ افتراضي فارغ ويتم الإعلان عن جميع الخصائص. السؤال التالي هو: لماذا النهج الأول أفضل؟

مقارنة إنشاء الكيان


دعنا نقارن التعليمات البرمجية للحصول على البيانات على العديد من الكتب من json وإنشاء مثيلات لفصول Book على أساسهم.

أ. النهج القياسي


 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++ }); } 

ب. نمط DDD


 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 في المُنشئ. يمكن إعلان مُنشئ BookAuthor بمستوى الوصول الداخلي. بهذه الطريقة يمكننا منع إنشاء علاقات خارج DAL.

كما لاحظت ، فإن مقدار الكود لإنشاء كيان هو نفسه تقريبا في كلتا الحالتين. إذن لماذا أسلوب DDD أفضل؟ نمط DDD هو الأفضل في ذلك:

  1. يتحكم في الوصول. يتم استبعاد التغيير العرضي للممتلكات. يحدث أي تغيير من خلال المنشئ أو الطريقة العامة بالاسم المقابل. من الواضح ما يحدث.
  2. يتوافق مع DRY (لا تكرر نفسك). قد تحتاج إلى إنشاء مثيلات Book في عدة أماكن. رمز المهمة في المنشئ ولا يلزمك تكراره في عدة أماكن.
  3. يخفي التعقيد. تحتوي فئة Book على خاصيتين: ActualPrice و OrgPrice. يجب أن تكون كلتا القيمتين متساوية عند إنشاء كتاب جديد. في نهج قياسي ، يجب أن يكون كل مطور على علم بذلك. في مقاربة DDD ، يكفي أن يعرف مطور فصول الكتب عنها. سيتعرف الباقون على هذه القاعدة لأنها مكتوبة صراحة في المنشئ.
  4. يخفي خلق الكلي. في الطريقة القياسية ، يجب على المطور إنشاء مثيل BookAuthor يدويًا. في نمط DDD ، يتم تغليف هذا التعقيد لرمز الاتصال.
  5. يسمح للخصائص أن يكون لها حق وصول للكتابة
  6. أحد أسباب استخدام DDD هو قفل الكيان ، أي لا تعطي القدرة على تغيير الخصائص مباشرة. دعونا نقارن عملية التغيير مع وبدون DDD.

تغيير خاصية المقارنة


يسمي إريك إيفانز إحدى المزايا الرئيسية للكيانات ذات نمط DDD بما يلي: "إنها تنقل قرارات التصميم بشأن الوصول إلى الكائنات".
ملاحظة مترجم. العبارة الأصلية صعبة الترجمة إلى اللغة الروسية. في هذه الحالة ، تُعد قرارات التصميم بمثابة قرارات تُتخذ بشأن كيفية عمل البرنامج. هذا يعني أنه تمت مناقشة القرارات وتأكيدها. التعليمة البرمجية مع مُنشئي تهيئة الكيانات والأساليب بشكل صحيح مع الأسماء الصحيحة التي تعكس معنى العمليات تخبر المطور بشكل صريح أن تعيينات قيم معينة تم إجراؤها عن قصد ، وليس عن طريق الخطأ ، وليست نزوة لمطور آخر أو تفاصيل التنفيذ.
أنا أفهم هذه العبارة على النحو التالي.

  1. اجعل من الواضح كيفية تعديل البيانات داخل الكيان والبيانات التي يجب تغييرها معًا.
  2. اجعل الأمر واضحًا عندما لا يجب تعديل بيانات معينة في الكيان.
دعنا نقارن بين النهجين. المثال الأول بسيط ، والثاني أكثر تعقيدًا.

1. تغيير تاريخ النشر


لنفترض أننا نريد العمل أولاً مع مسودة كتاب ثم نشره فقط. في وقت كتابة المسودة ، يتم تحديد تاريخ نشر تقديري ، والذي من المرجح أن يتم تغييره أثناء عملية التحرير. لتخزين تاريخ النشر ، سوف نستخدم خاصية PublishOn.

أ. الكيان بالممتلكات العامة


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

ب. كيان نمط DDD


في نمط DDD ، يتم الإعلان عن محدد الملكية ، لذا سنستخدم طريقة وصول متخصصة.

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

هاتين الحالتين هي نفسها تقريبا. نسخة DDD أطول قليلاً. ولكن لا يزال هناك فرق. في نمط DDD ، تعرف بالتأكيد أنه يمكن تغيير تاريخ النشر لأن هناك طريقة تحمل اسمًا واضحًا. أنت تعرف أيضًا أنه لا يمكنك تغيير الناشر لأن خاصية Publisher لا تحتوي على طريقة مناسبة للتغيير. ستكون هذه المعلومات مفيدة لأي مبرمج يعمل مع فصل كتاب.

2. إدارة الخصم للكتاب


شرط آخر هو أننا يجب أن نكون قادرين على إدارة الخصومات. يتكون الخصم من سعر جديد وتعليق ، على سبيل المثال ، "50٪ قبل نهاية هذا الأسبوع!"

تنفيذ هذه القاعدة بسيط ولكنه ليس واضحًا جدًا.

  1. الخاصية OrgPrice هو السعر دون خصم.
  2. ActualPrice - السعر الحالي الذي يتم بيع الكتاب به. إذا كان الخصم ساري المفعول ، فسيختلف السعر الحالي عن سعر OrgPrice حسب حجم الخصم. إذا لم يكن كذلك ، فإن قيمة الخصائص ستكون متساوية.
  3. يجب أن تحتوي الخاصية PromotionText على نص الخصم إذا تم تطبيق الخصم أو لاغٍ إذا كان الخصم غير مطبق حاليًا.

القواعد واضحة جدًا للشخص الذي قام بتنفيذها. ومع ذلك ، لمطور آخر ، على سبيل المثال ، تطوير واجهة مستخدم لإضافة خصم. تؤدي إضافة أساليب 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: إضافة تعليق PromotionalText مطلوب. يتحقق الأسلوب من أن النص غير فارغ. بسبب يمكن للمستخدم تصحيح هذا الخطأ ، حيث تقوم الطريقة بإرجاع قائمة بالأخطاء لتصحيحها.
  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; } 

هذان المثالان مختلفان للغاية عن بعضهما البعض. في المثال الأول ، يعد تغيير خاصية PublishOn أمرًا بسيطًا إلى الحد الذي يجعل التنفيذ القياسي جيدًا. في المثال الثاني ، تفاصيل التنفيذ ليست واضحة للشخص الذي لم يعمل مع فئة الكتاب. في الحالة الثانية ، يخفي نمط DDD مع أساليب الوصول المتخصصة تفاصيل التنفيذ ويجعل حياة المطورين الآخرين أسهل. أيضًا ، في المثال الثاني ، يحتوي الرمز على منطق الأعمال. على الرغم من أن مقدار المنطق صغير ، إلا أنه يمكننا تخزينه مباشرةً في طرق الوصول وإرجاع قائمة بالأخطاء إذا لم يتم استخدام الطريقة بشكل صحيح.

3. العمل مع مجمع - جمع التعليقات الملكية


تقدم DDD العمل مع الوحدة فقط من خلال الجذر. في حالتنا ، فإن خاصية المراجعات تخلق مشاكل. حتى إذا تم الإعلان عن setter كخصوصية ، فلا يزال بإمكان المطور إضافة أو إزالة كائنات باستخدام أساليب الإضافة والإزالة ، أو حتى استدعاء الطريقة الواضحة لمسح المجموعة بأكملها. هنا ، ستساعدنا ميزة 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: لا أتعمد تهيئة حقل المعاينات في مُنشئ بلا معلمات خاص يستخدمه EF Core عند تحميل كيانات من قاعدة البيانات. يسمح هذا الرمز الخاص بي لتحديد ما إذا كان قد تم تحميل المجموعة باستخدام .Include method (p => p.Reviews). في المنشئ العام ، أقوم بتهيئة الحقل ، لذلك لن يحدث NRE عند العمل مع الكيان الذي تم إنشاؤه.
  2. الأسطر 8-12: إذا لم يتم تحميل مجموعة المراجعات ، يجب أن يستخدم الرمز DbContext للتهيئة.
  3. الأسطر 13-16: إذا تم إنشاء الكتاب بنجاح واحتوى على معرّف ، فأنا أستخدم تقنية أخرى لإضافة مراجعة: ببساطة أقوم بتثبيت مفتاح خارجي في مثيل لفئة المراجعة وأكتبه في قاعدة البيانات. تم توضيح ذلك بمزيد من التفصيل في القسم 3.4.5 من كتابي.
  4. السطر 19: إذا كنا هنا ، فهناك مشكلة ما في منطق الكود. لذلك أنا رمي استثناء.

لقد قمت بتصميم جميع طرق الوصول الخاصة بي للحالات المعكوسة حيث يتم تحميل كيان الجذر فقط. كيفية تحديث الوحدة حسب تقدير الأساليب. قد تحتاج إلى تحميل كيانات إضافية.

الخاتمة


لإنشاء كيانات بنمط DDD باستخدام EF Core ، يجب عليك الالتزام بالقواعد التالية:

  1. إنشاء المنشئات العامة لإنشاء مثيلات فئة مهيأة بشكل صحيح. إذا حدثت أخطاء أثناء عملية الإنشاء التي يمكن للمستخدم تصحيحها ، فقم بإنشاء الكائن لا يستخدم المنشئ العام ، ولكن باستخدام طريقة المصنع التي تُرجع الحالة <T> ، حيث T هو نوع الكيان الذي يتم إنشاؤه
  2. جميع الممتلكات هي حراس الملكية. أي جميع الخصائص للقراءة فقط خارج الفصل.
  3. بالنسبة لخصائص التنقل للمجموعة ، قم بتعريف حقول النسخ الاحتياطي ، ونوع الخاصية العامة يعلن IEnumerable <T>. هذا سيمنع المطورين الآخرين من تغيير المجموعات بشكل لا يمكن السيطرة عليه.
  4. بدلاً من المستوطنين العموميين ، قم بإنشاء طرق عامة لجميع عمليات تغيير الكائن المسموح بها. يجب أن تُرجع هذه الطرق باطلة إذا لم تنجح العملية بسبب خطأ يمكن للمستخدم إصلاحه أو الحالة <T> إذا أمكن ذلك.
  5. نطاق مسؤولية كيان المسائل. أعتقد أنه من الأفضل قصر الكيانات على تغيير الفصل نفسه والفئات الأخرى داخل المجموعة ، ولكن ليس خارجها. يجب أن تقتصر قواعد التحقق من الصحة على التحقق من صحة إنشاء وتغيير حالة الكيانات. أي لا أتحقق من قواعد العمل مثل أرصدة الأسهم. هناك رمز منطق عمل خاص لهذا الغرض.
  6. يجب أن تفترض أساليب تغيير الحالة أنه يتم تحميل جذر التجميع فقط. إذا احتجت إحدى الطرق إلى تحميل بيانات أخرى ، فيجب عليها التعامل معها بمفردها.
  7. يجب أن تفترض أساليب تغيير الحالة أنه يتم تحميل جذر التجميع فقط. إذا احتجت إحدى الطرق إلى تحميل بيانات أخرى ، فيجب عليها التعامل معها بمفردها. هذا النهج يبسط استخدام الكيانات من قبل المطورين الآخرين.

إيجابيات وسلبيات الكيانات DDD عند العمل مع EF الأساسية


أنا أحب النهج النقدي لأي نمط أو هندسة. إليك ما أفكر في استخدام كيانات DDD.

الايجابيات


  1. استخدام أساليب متخصصة لتغيير الحالة هو نهج أنظف. هذا بالتأكيد حل جيد ، ببساطة لأن الأساليب المسماة بشكل صحيح تكشف عن نوايا الكود بشكل أفضل وتوضح ما يمكن تغييره ولا يمكن تغييره. بالإضافة إلى ذلك ، يمكن للطرق إرجاع قائمة بالأخطاء إذا كان بإمكان المستخدم إصلاحها.
  2. تغيير المجاميع من خلال الجذر فقط يعمل بشكل جيد
  3. يتم الآن إخفاء تفاصيل علاقة رأس بأطراف بين فصول الكتاب والمراجعة للمستخدم. التغليف هو مبدأ أساسي من OOP.
  4. يتيح لك استخدام المنشئات المتخصصة التأكد من أن الكيانات يتم إنشاؤها وضمان أن تتم تهيئتها بشكل صحيح.
  5. إن نقل رمز التهيئة إلى المنشئ يقلل بشكل كبير من احتمالية عدم قيام المطور بتفسير كيفية تهيئة الفصل بشكل صحيح.

سلبيات


  1. يحتوي نهجي على تبعيات على تنفيذ EF Core.
  2. بعض الناس يسميها حتى المضادة للنمط. المشكلة هي أنه الآن تعتمد كيانات طراز الموضوع على رمز الوصول إلى قاعدة البيانات. من حيث DDD ، وهذا أمر سيء. أدركت أنه إذا لم أفعل ذلك ، فسيتعين علي الاعتماد على المتصل لمعرفة ما يجب تحميله. هذا النهج يكسر مبدأ الفصل بين المخاوف.
  3. DDD يفرض عليك كتابة المزيد من التعليمات البرمجية.

هل حقا يستحق كل هذا العناء في الحالات البسيطة ، مثل تحديث تاريخ نشر الكتاب؟
كما ترون ، أنا أحب نهج DDD. ومع ذلك ، فقد استغرق الأمر بعض الوقت حتى أقوم بتكوينه بشكل صحيح ، ولكن في الوقت الحالي ، تمت تسوية النهج بالفعل وأنا أطبقه في المشروعات التي أعمل عليها. لقد تمكنت بالفعل من تجربة هذا الأسلوب في المشاريع الصغيرة وأنا راضٍ ، ولكن لم يتم العثور على جميع إيجابيات وسلبيات عندما استخدمه في المشاريع الكبيرة.

لم يكن قراري بالسماح باستخدام التعليمات البرمجية الخاصة بـ EFCore في وسيطات أساليب كيان طراز الكيان بسيطًا. حاولت منع ذلك ، لكن في النهاية توصلت إلى استنتاج مفاده أن رمز الاتصال يجب أن يقوم بتحميل الكثير من خصائص التنقل. وإذا لم يتم ذلك ، فلن يتم تطبيق التغيير ببساطة دون أي أخطاء (خاصة في العلاقة الفردية). لم يكن هذا مقبولًا بالنسبة لي ، لذلك سمحت باستخدام EF Core داخل بعض الأساليب (ولكن ليس المنشئات).

الجانب السيئ الآخر هو أن DDD يجبرك على كتابة رمز أكثر بكثير لعمليات CRUD. ما زلت غير متأكد من الاستمرار في تناول الصبار وكتابة طرق منفصلة لجميع الخصائص ، أو في بعض الحالات ، يجدر الابتعاد عن التطرف الراديكالي. أعلم أن هناك مجرد عربة وشاحنة صغيرة من CRUD الممل ، وهو أسهل في الكتابة مباشرة. العمل فقط على المشاريع الحقيقية سيظهر أيهما أفضل.

جوانب DDD الأخرى غير المشمولة في هذه المقالة


لقد تبين أن المقالة طويلة جدًا ، لذا سأنتهي هنا. ولكن هذا يعني أنه لا يزال هناك الكثير من المواد غير المكشوف عنها. لقد كتبت بالفعل عن شيء ما ، وعن شيء سأكتبه في المستقبل القريب. إليك ما تبقى في الخارج:

  1. منطق الأعمال و DDD. لقد كنت أستخدم مفاهيم DDD في رمز منطق العمل لعدة سنوات ، وباستخدام الميزات الجديدة لبرنامج EF Core ، أتوقع أن أستطيع نقل بعض المنطق إلى رمز الكيان. اقرأ المقال "مرة أخرى حول بنية طبقة منطق الأعمال باستخدام إطار عمل الكيان (Core و v6)"
  2. DDD ونمط المخزون. إريك إيفانز يوصي باستخدام مستودع من أجل الوصول إلى البيانات مجردة. , «» EF Core – . لماذا؟ - .
  3. DBContext' / (bounded contexts). DbContext'. , BookContext Book OrderContext, . , « » , . , .

كل التعليمات البرمجية لهذه المقالة متوفرة في مستودع GenericBizRunner على جيثب . يحتوي هذا المستودع على مثال تطبيق ASP.NET Core مع طرق وصول متخصصة لتعديل فئة الكتاب. يمكنك استنساخ المستودع وتشغيل التطبيق محليًا. ويستخدم في الذاكرة Sqlite كقاعدة بيانات ، لذلك يجب أن تعمل على أي بنية تحتية.

تنمية سعيدة!

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


All Articles