ข้อผิดพลาดของการออกแบบโดเมนขับเคลื่อนด้วย Entity Framework


12

บทเรียนจำนวนมากเกี่ยวกับ DDD ที่ฉันศึกษาส่วนใหญ่จะครอบคลุมทฤษฎี พวกเขาทั้งหมดมีตัวอย่างรหัสพื้นฐาน (Pluralsight และคล้ายคลึงกัน)

บางคนพยายามสร้างบทเรียนที่ครอบคลุม DDD ด้วย EF บนเว็บ หากคุณเริ่มศึกษาพวกเขาเพียงชั่วครู่ - คุณสังเกตได้อย่างรวดเร็วว่าพวกเขาแตกต่างกันมาก บางคนแนะนำให้แอพพลิเคชั่นมีน้อยที่สุดและเพื่อหลีกเลี่ยงการแนะนำเลเยอร์เพิ่มเติมเช่นที่เก็บข้อมูลด้านบนของ EFคนอื่น ๆ กำลังสร้างเลเยอร์เพิ่มเติมอย่างแน่นอนซึ่งมักจะละเมิด SRP ด้วยการฉีดDbContextเข้าไปใน Aggregate Roots

ฉันขอโทษอย่างมากถ้าฉันถามคำถามตามความคิดเห็น แต่ ...

เมื่อมาถึงการปฏิบัติ - Entity Framework เป็นหนึ่งใน ORMs ที่ทรงพลังและใช้กันอย่างแพร่หลาย คุณจะไม่พบหลักสูตรที่ครอบคลุมที่ครอบคลุม DDD ด้วยโชคไม่ดี


ประเด็นสำคัญ:

  • Entity Framework นำ UoW & Repository ( DbSet) ออกจากกล่อง

  • รุ่นของคุณกับ EF มีคุณสมบัติการนำทาง

  • กับ EF ทุกรุ่นของยี่ห้อมักจะใช้ได้ปิดDbContext(พวกเขาจะแสดงเป็นDbSet)

ผิดพลาด:

  • คุณไม่สามารถรับประกันได้ว่ารุ่นลูกของคุณจะได้รับผลกระทบผ่านทาง Aggregate Root เท่านั้นโมเดลของคุณมีคุณสมบัติการนำทางและเป็นไปได้ที่จะแก้ไขและเรียกใช้dbContext.SaveChanges()

  • ด้วยDbContextคุณสามารถเข้าถึงทุกรุ่นของคุณดังนั้นหลีกเลี่ยง Aggregate Root

  • คุณสามารถ จำกัด การเข้าถึงเด็กวัตถุรากผ่านทางModelBuilderในOnModelCreatingวิธีการโดยการทำเครื่องหมายพวกเขาเป็นทุ่งนา - ผมก็ยังไม่เชื่อว่ามันเป็นวิธีที่จะไปเกี่ยวกับ DDD บวกมันยากที่จะประเมินสิ่งที่ชนิดของการผจญภัยนี้อาจนำไปสู่ในอนาคต ( ค่อนข้างสงสัย )

ความขัดแย้ง:

  • หากไม่มีการใช้พื้นที่เก็บข้อมูลอีกชั้นหนึ่งซึ่งส่งคืนผลรวมเราไม่สามารถแก้ไขข้อผิดพลาดที่กล่าวข้างต้นได้บางส่วน

  • ด้วยการนำพื้นที่เก็บข้อมูลชั้นพิเศษมาใช้ทำให้เราไม่ต้องสนใจคุณสมบัติที่มีอยู่ในตัวของ EF (ทุกอย่างDbSetเป็น repo อยู่แล้ว) และแอพที่ซับซ้อนเกินความจำเป็น


บทสรุปของฉัน:

โปรดให้อภัยฉันไม่รู้ แต่อยู่บนพื้นฐานของข้อมูลดังกล่าวข้างต้น - มันทั้ง Entity Framework อาจจะไม่เพียงพอสำหรับโดเมนที่ขับเคลื่อนด้วยการออกแบบหรือการออกแบบโดเมนขับเคลื่อนเป็นที่ไม่สมบูรณ์และล้าสมัยวิธี

ฉันสงสัยว่าแต่ละวิธีมีข้อดี แต่ตอนนี้ฉันหลงทางไปแล้วและไม่มีความคิดเพียงเล็กน้อยเกี่ยวกับวิธีการกระทบยอด EF กับ DDD


ถ้าฉันผิด - อย่างน้อยใครก็สามารถอธิบายรายละเอียดของชุดคำสั่งง่ายๆ (หรือให้ตัวอย่างรหัสที่เหมาะสม) ว่าจะไปเกี่ยวกับ DDD กับ EF ได้ไหม?


ฉันมีรายละเอียดขั้นตอนที่นี่ตามความเข้าใจของฉันเกี่ยวกับการทำงานของ EF ขั้นตอนเหล่านั้นยังไม่สามารถจัดการกับปัญหาในการเข้าถึงเด็ก ๆ ด้วยการนำทาง คุณสมบัติหรือโดย DbSets ปิด DbContext
อเล็กซ์เฮอร์แมน

คำตอบ:


8

DDD และ EF แทบจะไม่มีอะไรเกี่ยวข้องเลย

DDD เป็นแนวคิดการสร้างแบบจำลอง มันหมายถึงคิดเกี่ยวกับโดเมน, ข้อกำหนดทางธุรกิจและรูปแบบเหล่านั้น โดยเฉพาะอย่างยิ่งในบริบทของการวางแนววัตถุหมายถึงการสร้างการออกแบบที่สะท้อนถึงหน้าที่และความสามารถทางธุรกิจ

EF เป็นเทคโนโลยีติดตา มันเกี่ยวข้องกับข้อมูลและบันทึกฐานข้อมูลเป็นหลัก

สองคนนี้หย่าร้างกันอย่างรวดเร็ว การออกแบบ DDD อาจใช้ EF ในบางรูปแบบภายใต้ประทุน แต่ทั้งสองไม่ควรมีปฏิสัมพันธ์ในทางอื่น

การตีความการออกแบบโดเมนขับเคลื่อนบางอย่างสนับสนุนการสร้างแบบจำลองข้อมูลจริง ๆ และฉันคิดว่านี่เป็นคำถามของคุณ ในการแปลความหมายนี้ "เอนทิตี" และ "ออบเจ็กต์ตามตัวอักษร" นั้นเป็นฟังก์ชั่นที่ไม่ต้องอาศัยข้อมูลเพียงอย่างเดียวและการออกแบบนั้นเกี่ยวข้องกับคุณสมบัติของคุณสมบัติเหล่านี้และความสัมพันธ์ระหว่างกัน ในบริบทนี้ DDD กับ EF อาจเกิดขึ้น

อย่างไรก็ตามการตีความนี้มีข้อบกพร่องและฉันขอแนะนำอย่างยิ่งให้ละเว้นโดยสิ้นเชิง

โดยสรุป : DDD และ EF ไม่ได้มีลักษณะเฉพาะตัวซึ่งกันและกันพวกเขาไม่เกี่ยวข้องกันจริง ๆ ตราบใดที่คุณทำแบบจำลองวัตถุที่เหมาะสมและไม่ใช่แบบจำลองข้อมูล วัตถุ DDD ไม่ควรอยู่ในรูปร่างหรือรูปแบบใด ๆ เป็นสิ่งประดิษฐ์ของ EF หน่วยงาน DDD ไม่ควรเป็น "เอนทิตี" ของ EF เช่นกัน ภายในฟังก์ชั่นที่เกี่ยวข้องกับธุรกิจการออกแบบ DDD อาจใช้ EF กับวัตถุข้อมูลที่เกี่ยวข้อง แต่สิ่งเหล่านั้นควรถูกซ่อนอยู่ภายใต้ส่วนต่อประสานพฤติกรรมที่เกี่ยวข้องกับธุรกิจ


1
EF เป็นเพียงการประหยัดเวลา การติดตามการเปลี่ยนแปลงและการคงอยู่ของมวลรวมเป็นที่ที่ EF ช่วยคุณได้มากแล้ว น่าเสียดายที่ปัจจุบันยังไม่มีวิธีกำหนดรูปร่างของมวลรวมที่ระดับการกำหนดค่า
Pavel Voronin

6

รักษา EF สำหรับสิ่งที่เป็นเช่นไลบรารีการเข้าถึงข้อมูลซึ่งมีการพิมพ์อย่างรุนแรงเพียงเล็กน้อยกว่า ADO.NET แบบดิบ ฉันจะไม่แนะนำให้สร้างแบบจำลองโดเมนของคุณโดยใช้คลาสเอนทิตี้ของ EF เหมือนกับที่ฉันไม่แนะนำให้ทำแบบจำลองโดเมนโดยใช้ชุดข้อมูลดิบหรือ DataTable

ฉันเข้าใจว่า EF กำลังขายเป็นทางลัดระหว่างการเข้าถึงฐานข้อมูลและการสร้างแบบจำลองโดเมนอย่างไรก็ตามวิธีการนี้มีข้อบกพร่องอย่างแท้จริงเนื่องจากเป็นปัญหาที่สองที่ไม่เกี่ยวข้องกัน มีความพยายามอื่น ๆ ใน. NET เพื่อให้ชั้นเรียนดำเนินการบางสิ่งที่ไม่เกี่ยวข้องอย่างสมบูรณ์ (เช่น. NET Remoting) และพวกเขาก็ไม่ได้จบลงด้วยดี

ทำ DDD โดยใช้คลาส POCO และอย่าให้สคีมาฐานข้อมูลขับการออกแบบของคุณ รักษา EF ไว้ในพื้นที่เก็บข้อมูล / ชั้นการคงอยู่และอย่าให้เอนทิตีของ EF รั่วไหลออกไปข้างนอก


5

Entity Framework นำ UoW & Repository (DbSet) ออกจากกล่อง

เลขที่

Entity Framework abstractions สร้างด้วย ORM ไม่ใช่ DDD สิ่งที่DbSetเป็นนามธรรมใน Entity Framework ทุกรุ่นไม่มีที่ไหนใกล้กับความเรียบง่ายของพื้นที่เก็บข้อมูล DDD - ไม่ต้องพูดถึงDbContextซึ่งทำให้มีสิ่งหนึ่งล้านล้านมากกว่า UnitOfWork

นี่คือรายการองค์ประกอบที่ไม่ครบถ้วนสมบูรณ์ในนามธรรมของ EF Core 2.1 DbSet<TEntity>ที่เราไม่ต้องการใน DDD:

  • Attach(TEntity) และพี่น้องทั้งหลาย
  • Find(Object[])
  • Update(TEntity) และพี่น้องทั้งหลาย
  • การดำเนินการ IQueryable

นอกเหนือจากการลากไปตามการพึ่งพาที่ไม่จำเป็นกับพวกเขาเหล่านี้ปิดบังเจตนาของพื้นที่เก็บข้อมูลซึ่งโดยปกติแล้วจะเปิดเผยพฤติกรรมการเก็บรวบรวมที่ง่ายมาก นอกจากนี้สิ่งที่น่าฉงนสนเท่ห์ก็เป็นสิ่งล่อใจให้นักพัฒนาจับคู่ตัวเองกับ EF มากเกินไปและเป็นภัยคุกคามต่อการแยกความกังวล

ที่บรรทัดล่าง: คุณต้องห่อ fatties เหล่านี้เป็นแนวคิดที่ดีคล่องตัวและคาดเดาสิ่งที่หมายถึงการแนะนำชั้นเรียนพิเศษ

ตัวอย่างที่ชัดเจนเกี่ยวกับสิ่งที่คุณสามารถทำได้กับ EF และ DDD (แม้ว่าจะมีบางมุมมองที่แสดงให้เห็นว่าเป็นปัญหา): https://kalele.io/blog-posts/modeling-aggregates-with-ddd-and-entity-framework/

คนอื่น ๆ กำลังสร้างเลเยอร์เพิ่มเติมอย่างแน่นอนซึ่งมักจะละเมิด SRP ด้วยการฉีด DbContext เข้าไปใน Aggregate Roots

ฉันไม่เห็นความเชื่อมโยงระหว่างสองส่วนของประโยคนี้ ไม่ว่าวิธีการใดมีสิ่งหนึ่งใน DDD ที่เรียกว่า Application Service และนั่นคือสิ่งที่คุณจัดการหน่วยการทำงาน / พื้นที่เก็บข้อมูล (หรือDbContext) ไม่อยู่ในรากรวม

ในขณะที่มันอาจเป็นวิธีการที่ถูกต้องถ้ามันเป็นการแลกเปลี่ยนทางการศึกษาแนวโน้มต่อต้าน "พื้นที่เก็บข้อมูลล่าสุด" Entity Framework minimalism "ล่าสุดเป็นความหลง มันโทษรูปแบบ DDD สำหรับแรงเสียดทานที่เกิดขึ้นกับ Entity Framework เมื่อเป็นผู้สร้าง EF จริงๆที่ไม่ได้ทำอะไรเพื่อให้กรอบของพวกเขาสอดคล้องกับแนวทางปฏิบัติที่ดีที่สุดนอกกรอบ ในขณะที่พวกเขาได้รับการควบคู่ไปกับกรอบที่มากกับปัญหาทั้งหมดในแง่ของความปลอดภัยของรหัสและการบำรุงรักษาที่สามารถตามมา


2

ความขัดแย้ง:

หากไม่มีการใช้พื้นที่เก็บข้อมูลอีกชั้นซึ่งให้ผลตอบแทนรวมเราไม่สามารถแก้ไขข้อผิดพลาดที่กล่าวข้างต้นได้บางส่วน

ด้วยการนำพื้นที่เก็บข้อมูลชั้นพิเศษมาใช้ทำให้เราไม่ต้องสนใจคุณสมบัติที่มีอยู่ในตัวของ EF (ทุก DbSet เป็น repo อยู่แล้ว) และแอพที่ซับซ้อนเกินความจำเป็น

ฉันได้ใช้วิธีการที่ Aggregate ทุกคนได้รับ DBContext ของตัวเองการจับคู่สิ่งที่จำเป็นสำหรับการรวม ฉันคิดว่าสิ่งนี้ได้รับการอธิบายโดย Julie Lerman

สิ่งนี้ได้ผลดีมาก แต่อาจไม่เพียงพอสำหรับโมเดลที่น่าสนใจมากขึ้นซึ่งคุณไม่ต้องการเชื่อมโยงแนวคิดของคุณกับเอนทิตีของคุณ


เห็นวิดีโอนี้ด้วยเช่นกันdddcommunity.org/ddd-contributors/ …
Alex Herman

มีประโยชน์ใด ๆ ของ DBContext ต่อวิธีการรวม? นี่เป็นวิธีเริ่มต้นในการใช้ DDD กับ EF หรือไม่
Alex Herman

Julie Lerman ไม่ได้หมายถึง DbContext ต่อบริบทที่ถูก จำกัด หรือไม่
Mvision

0

เพียงต้องการแบ่งปันโซลูชันที่เป็นไปได้เพื่อประกอบการพิจารณา:

  1. หลีกเลี่ยงการอ้างอิงโครงการ EF ใน Service Layer โดยตรง

  2. สร้างเลเยอร์พื้นที่เก็บข้อมูลพิเศษ(ใช้โครงการ EF และส่งกลับ Aggregate Root)

  3. อ้างอิง Repository Layer ในโครงการเลเยอร์บริการ

สถาปัตยกรรม :

  • UI

  • เลเยอร์ควบคุม

  • ชั้นบริการ

  • Repository Layer

  • Entity Framework

  • โครงการหลัก (ประกอบด้วยโมเดล EF)


ข้อผิดพลาดที่ฉันเห็นด้วยวิธีนี้:

  • ถ้า Repository ส่งคืนค่าAggregate Rootไม่เป็นต้นไม้ต้นแบบของ EF (เช่นเราคืนออบเจกต์ที่ถูกแมป) - เรากำลังสูญเสียความสามารถของ EF ในการติดตามการเปลี่ยนแปลง

  • ถ้า Aggregate Root เป็นรุ่น EF - คุณสมบัติการนำทางทั้งหมดยังคงมีอยู่แม้ว่าเราจะไม่สามารถจัดการได้DbContext(เราไม่ได้อ้างอิงโครงการ EF ใน Service Layer)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.