แอปพลิเคชัน ASP.NET MVC ควรใช้ Entity Framework โดยตรงเป็นโมเดลหรือไม่


22

ฉันกำลังสร้างแอปพลิเคชัน MVC แรกของฉันใน Visual Studio 2013 (MVC 5) และฉันยังไม่ชัดเจนเกี่ยวกับวิธีที่ดีที่สุดในการตั้งค่าแบบจำลองของฉัน

ฉันสร้างโมเดลเอนทิตี้ของเฟรมเวิร์กโดยใช้รหัส - แรกจากฐานข้อมูลที่มีอยู่ สัญชาตญาณแรกของฉันคือการสร้างคลาสตัวกลางที่จะเป็นโมเดลที่ใช้โดยมุมมองและให้คลาสเหล่านั้นทำงานกับคลาสเฟรมเวิร์กเอนทิตี

ในขณะที่ฉันกำลังเขียนคลาสคนกลางฉันรู้ว่าฉันเพิ่งจะติดตั้งสิ่งต่าง ๆ มากมายที่ชั้นเรียนของ EF ได้ทำกับ setter ส่วนตัวเป็นครั้งคราวหรือส่งจากประเภทข้อมูลหนึ่งไปยังอีกประเภทหนึ่ง ดังนั้นดูเหมือนว่าจะเสียเปล่า

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


1
สิ่งนี้อาจช่วยได้: programmers.stackexchange.com/questions/123011/…
oasten

หากคุณใช้รหัสเป็นอันดับแรกแสดงว่าไม่มีฐานข้อมูลที่มีอยู่แล้วไม่ใช่หรือ?
Isaac Kleinman

1
ด้วย EF 6.1+ คุณสามารถสร้างแบบจำลองรหัสแรกจากฐานข้อมูลที่มีอยู่ ดูบทความ MSDN นี้: msdn.microsoft.com/en-au/data/jj200620.aspx
Mike D.

คำตอบ:


23

ในแอปพลิเคชันของฉันฉันได้แยกสิ่งต่าง ๆ ออกเสมอโดยมีโมเดลที่แตกต่างกันสำหรับฐานข้อมูล (Entity Framework) และ MVC ฉันได้แยกสิ่งเหล่านี้ออกเป็นโครงการต่าง ๆ เช่นกัน:

  • Example.Entities - มีเอนทิตีของฉันสำหรับ EF และบริบท DB สำหรับเข้าถึงพวกเขา
  • Example.Models - มีรุ่น MVC
  • ตัวอย่างเว็บ - โปรแกรมประยุกต์บนเว็บ ขึ้นอยู่กับทั้งสองโดเมนและตัวอย่าง

แทนที่จะถือการอ้างอิงไปยังวัตถุอื่น ๆ เช่นเอนทิตีโดเมนทำรุ่น MVC เก็บ ID เป็นจำนวนเต็ม

เมื่อมีการร้องขอ GET สำหรับเพจตัวควบคุม MVC จะดำเนินการค้นหาฐานข้อมูลซึ่งส่งคืนเอนทิตี ฉันได้เขียนวิธี "ตัวแปลง" ที่ใช้เอนทิตีโดเมนและแปลงเป็นรูปแบบ MVC มีวิธีการอื่น ๆ ที่ทำตรงกันข้าม (จากรูปแบบ MVC ไปยังเอนทิตีโดเมน) โมเดลจะถูกส่งผ่านไปยังมุมมองและทำให้กับไคลเอ็นต์

เมื่อมีคำขอ POST เข้ามาคอนโทรลเลอร์ MVC จะได้รับรุ่น MVC เมธอดตัวแปลงแปลงสิ่งนี้เป็นเอนทิตีโดเมน วิธีนี้ยังทำการตรวจสอบความถูกต้องใด ๆ ที่ไม่สามารถแสดงเป็นคุณลักษณะได้และตรวจสอบให้แน่ใจว่าหากนิติบุคคลมีอยู่แล้วว่าเรากำลังอัปเดตมากกว่าที่จะได้รับสิ่งใหม่ วิธีการมักจะมีลักษณะเช่นนี้:

public class PersonConverter
{
    public MyDatabaseContext _db;

    public PersonEntity Convert(PersonModel source)
    {
         PersonEntity destination = _db.People.Find(source.ID);

         if(destination == null)
             destination = new PersonEntity();

         destination.Name = source.Name;
         destination.Organisation = _db.Organisations.Find(source.OrganisationID);
         //etc

         return destination;
    }

    public PersonModel Convert(PersonEntity source)
    {
         PersonModel destination = new PersonModel()
         {
             Name = source.Name,
             OrganisationID = source.Organisation.ID,
             //etc
         };

         return destination;
    }
}

ด้วยการใช้วิธีการเหล่านี้ฉันจะลบความซ้ำซ้อนที่อาจเกิดขึ้นในแต่ละคอนโทรลเลอร์ การใช้ยาชื่อสามัญสามารถขจัดสิ่งซ้ำซ้อนได้อีก

การทำสิ่งต่าง ๆ ด้วยวิธีนี้มีประโยชน์หลายประการ:

  • คุณสามารถปรับแต่งแบบจำลองเพื่อมุมมองหรือการกระทำที่เฉพาะเจาะจง สมมติว่าคุณมีแบบฟอร์มการลงทะเบียนสำหรับบุคคลที่เมื่อส่งให้สร้างเอนทิตีที่แตกต่างกันมากมาย (บุคคลองค์กรที่อยู่) หากไม่มีรุ่น MVC แยกกันจะเป็นเรื่องยากมาก
  • ถ้าฉันต้องการส่งผ่านข้อมูลเพิ่มเติมไปยังมุมมองมากกว่าที่จะมีให้ในเอนทิตี้หรือรวมสองเอนทิตี้เข้าไว้ในโมเดลเดียวโมเดลฐานข้อมูลอันมีค่าของฉันจะไม่แตะต้องเลย
  • หากคุณเป็นอนุกรมรุ่น MVC เป็น JSON หรือ XML คุณจะได้รับรูปแบบทันทีที่ถูกทำให้เป็นอนุกรมไม่ใช่เอนทิตีอื่น ๆ ทุกตัวที่เชื่อมโยงกับโมเดลนี้

คำตอบที่ดีจะแนะนำให้ใช้ ValueInjector หรือสิ่งที่คล้ายกัน (ส่วนตัวฉันเกลียดออโตบอท) แทนการแมปคุณสมบัติด้วยตนเองจากคลาสหนึ่งไปอีกคลาสหนึ่ง
Rocklan

1
แทนที่จะเพิ่มคำตอบแยกกันฉันจะแสดงความคิดเห็นที่นี่ว่าในวิธีปฏิบัติ DDD "ตัวแปลง" และโมเดลแยกต่างหากสำหรับมุมมองของคุณจะถือว่าเป็นส่วนหนึ่งของ Application Service Layer โดยทั่วไปจะช่วยให้รูปแบบโดเมนของคุณซับซ้อนตามที่ต้องการพร้อมกับซ่อนความซับซ้อนนั้นจากแอปพลิเคชัน นอกจากนี้ยังป้องกันแอปพลิเคชันไม่ให้ถูกเปลี่ยนแปลงเนื่องจากการเปลี่ยนแปลงในรูปแบบโดเมน ASL จัดการการแปล
Michael Brown

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

1
คุณจะจัดการการแม็พคอลเลคชั่นได้อย่างไร ที่ดูเหมือนว่าจะได้รับความซับซ้อนมากขึ้นในการ EF6 ที่คุณสามารถไม่เพียงแค่สร้างรายการใหม่ของหน่วยงานที่มีการปรับปรุงเป็นเพียงแค่นี้อีกครั้งสร้างทุกอย่าง ...
เจอราร์ดวิลกินสัน

2
แทนที่จะเขียนคลาสตัวแปลงของคุณเองฉันขอแนะนำให้ใช้ไลบรารีAutomapperซึ่งเขียนขึ้นเพื่อแก้ไขปัญหานี้ มันเติบโตเต็มที่ตั้งแต่ปี 2014!
BenSmith

6

ฉันจะบอกว่ามันขึ้นอยู่กับใบสมัครของคุณ มันเป็นเพียงการทำ CRUD บริสุทธิ์โดยไม่มีตรรกะทางธุรกิจใด ๆ ? จากนั้นฉันจะใช้โมเดลของ EF โดยตรงในมุมมองของฉัน

ส่วนใหญ่มีตรรกะทางธุรกิจอย่างน้อยบางส่วนที่เกี่ยวข้องกับเลเยอร์ระหว่างโมเดลข้อมูล / EF และมุมมองอาจเป็นความคิดที่ดี ในกรณีนี้อาจเหมาะสมที่จะทำ "CQRS-lite" (ดูด้านล่าง) และใช้รุ่นที่แตกต่างกันเข้าและออกจากคอนโทรลเลอร์ของคุณ ส่วนใหญ่แล้วรุ่นที่อ่านจะมีความ "อ้วนขึ้น" มากกว่ารุ่นเขียน ...

อย่างไรก็ตามหากแอปพลิเคชันมีตรรกะทางธุรกิจจำนวนมากและ / หรือจำเป็นต้องขยายจำนวนมากฉันจะใช้หลักอย่างน้อยในการใช้ CQRS (Command Query Responsibility Segregation), DDD (Domain Driven Design) และการจัดหากิจกรรม จากนั้นสามารถใช้ EF เป็นส่วนหน้าของแบบจำลองการอ่าน

โปรดจำไว้ว่าคุณไม่จำเป็นต้องใช้กลยุทธ์ / รูปแบบเดียวกับแอปพลิเคชันทั้งหมดบางพื้นที่อาจเป็น CRUD ที่บริสุทธิ์และพื้นที่อื่น ๆ อาจมีตรรกะทางธุรกิจมากมาย ...

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