การฉีดพึ่งพากับโซลูชัน n-tier Entity Framework


12

ขณะนี้ฉันกำลังออกแบบโซลูชัน n-tier ซึ่งใช้ Entity Framework 5 (.net 4) เป็นกลยุทธ์การเข้าถึงข้อมูล แต่ฉันกังวลเกี่ยวกับวิธีรวมการฉีดพึ่งพาเพื่อให้สามารถทดสอบ / ยืดหยุ่นได้

เค้าโครงโซลูชันปัจจุบันของฉันมีดังนี้ (โซลูชันของฉันชื่อ Alcatraz):

Alcatraz.WebUI : การ asp.net เว็บฟอร์มโครงการส่วนติดต่อผู้ใช้ปลายด้านหน้าอ้างอิงโครงการAlcatraz.BusinessและAlcatraz.Data.Models

Alcatraz.Business : โครงการห้องสมุดระดับมีตรรกะทางธุรกิจโครงการอ้างอิงAlcatraz.Data.Access , Alcatraz.Data.Models

Alcatraz.Data.Access : ห้องสมุดชั้นโครงการบ้านAlcatrazModel.edmxและAlcatrazEntitiesDbContext อ้างอิงโครงการAlcatraz.Data.Models

Alcatraz.Data.Models : โครงการห้องสมุดคลาสมี POCO สำหรับรุ่น Alcatraz ไม่มีการอ้างอิง

วิสัยทัศน์ของฉันสำหรับวิธีการแก้ปัญหานี้จะทำงานเป็น web-UI จะยกตัวอย่างพื้นที่เก็บข้อมูลภายในห้องสมุดธุรกิจที่เก็บนี้จะมีการพึ่งพา (ผ่านตัวสร้าง) ของสตริงการเชื่อมต่อ (ไม่ใช่AlcatrazEntitiesอินสแตนซ์) web-ui จะรู้จักสตริงการเชื่อมต่อฐานข้อมูล แต่ไม่ใช่ว่าเป็นสตริงการเชื่อมต่อของเฟรมเวิร์กเอนทิตี

ในโครงการธุรกิจ:

public class InmateRepository : IInmateRepository
{
    private string _connectionString;

    public InmateRepository(string connectionString)
    {
        if (connectionString == null)
        {
            throw new ArgumentNullException("connectionString");
        }

        EntityConnectionStringBuilder connectionBuilder = new EntityConnectionStringBuilder();

        connectionBuilder.Metadata = "res://*/AlcatrazModel.csdl|res://*/AlcatrazModel.ssdl|res://*/AlcatrazModel.msl";
        connectionBuilder.Provider = "System.Data.SqlClient";
        connectionBuilder.ProviderConnectionString = connectionString;

        _connectionString = connectionBuilder.ToString();
    }

    public IQueryable<Inmate> GetAllInmates()
    {
        AlcatrazEntities ents = new AlcatrazEntities(_connectionString);

        return ents.Inmates;
    }
}

ใน Web UI:

IInmateRepository inmateRepo = new InmateRepository(@"data source=MATTHEW-PC\SQLEXPRESS;initial catalog=Alcatraz;integrated security=True;");

List<Inmate> deathRowInmates = inmateRepo.GetAllInmates().Where(i => i.OnDeathRow).ToList();

ฉันมีคำถามที่เกี่ยวข้องกับการออกแบบนี้

  1. การออกแบบนี้ทำให้รู้สึกถึงความสามารถของ Entity Frameworks หรือไม่? ฉันได้ยินมาว่า Entity framework ใช้รูปแบบหน่วยงานแล้วฉันจะเพิ่มเลเยอร์นามธรรมอีกชั้นหนึ่งโดยไม่จำเป็นหรือไม่

  2. ฉันไม่ต้องการให้ web-UI ของฉันสื่อสารโดยตรงกับ Entity Framework (หรืออ้างอิงถึงเรื่องนั้น) ฉันต้องการให้การเข้าถึงฐานข้อมูลทั้งหมดผ่านชั้นธุรกิจเหมือนในอนาคตฉันจะมีหลายโครงการที่ใช้เลเยอร์ธุรกิจเดียวกัน (บริการเว็บแอปพลิเคชัน windows ฯลฯ ) และฉันต้องการให้ง่ายต่อการดูแลรักษา / ปรับปรุงโดยให้ตรรกะทางธุรกิจในพื้นที่ส่วนกลางเดียว นี่เป็นวิธีที่เหมาะสมในการบรรลุเป้าหมายนี้หรือไม่?

  3. เลเยอร์ธุรกิจควรมีที่เก็บข้อมูลหรือควรอยู่ในเลเยอร์การเข้าถึงด้วยหรือไม่ หากพวกเขาอยู่ที่ไหนก็ดีการส่งผ่านสตริงการเชื่อมต่อเป็นการพึ่งพาที่ดีที่จะคิดหรือไม่?

ขอบคุณที่สละเวลาอ่าน!

คำตอบ:


11

วิธีที่คุณทำ DI นั้นผิด

ก่อนอื่นสตริงการเชื่อมต่ออยู่ในชั้นข้อมูล หรือในไฟล์ web.config

สิ่งที่เป็นนามธรรมถัดไปที่คุณจะติดต่อด้วยคือ DbContext ไม่ใช่สตริงการเชื่อมต่อ ที่เก็บของคุณไม่ควรรู้เกี่ยวกับสตริงการเชื่อมต่อ ตรรกะทางธุรกิจของคุณจะไม่ทราบเกี่ยวกับ DbContext ฯลฯ

UI ของคุณจะไม่มีความคิดและจะไม่ยกตัวอย่างสิ่งที่เกี่ยวข้องกับ EF

คำตอบที่เป็นรูปธรรมสำหรับคะแนนของคุณ:

  1. อย่าเพิ่ม abstractions จนกว่าคุณจะคุ้นเคยกับ EF มาก มันเพิ่ม abstractions ที่ดีเช่น UoW, การสืบค้น, การใช้ POCO เป็นต้น

  2. เพื่อให้ DI ทำงานได้คุณจะมี Composition Root ซึ่งอ้างอิงองค์ประกอบทั้งหมดที่จำเป็น นี่อาจเป็นหรือไม่ได้อยู่ในโครงการ WebUI หากไม่ใช่คุณควรคาดหวังว่าจะไม่อ้างอิง EF หรือเทคโนโลยีอื่น ๆ ที่เกี่ยวข้องกับข้อมูล

  3. หยุดตรงนี้ หยุดการเพิ่ม abstractions ให้กับ abstractions เริ่มต้นด้วยสถาปัตยกรรมโดยตรงและ 'ไร้เดียงสา' และพัฒนาเมื่อเวลาผ่านไป

Abstractions เป็นเครื่องมือในการจัดการกับความซับซ้อน การขาดความซับซ้อนหมายถึงไม่จำเป็นต้องมี abstractions (ยัง)


เพื่อให้ชัดเจนว่าฉันเข้าใจสิ่งที่คุณกำลังพูด: พื้นที่เก็บข้อมูล (ซึ่งอินเทอร์เฟซที่มีอยู่ในธุรกิจและคอนกรีตที่มีอยู่ใน Alcatraz.Data.Access?) ยอมรับDbContextว่าเป็นการพึ่งพา ชั้นธุรกิจมีพื้นที่เก็บข้อมูลเป็นการอ้างอิง สำหรับการฉีดพึ่งพาฉันทำด้วยตนเอง (ดังนั้นฉันเข้าใจว่าเกิดอะไรขึ้น) เหตุผลที่ฉันต้องการให้สามารถตั้งค่าสตริงการเชื่อมต่อบนDbContextคือฉันใช้ฐานข้อมูล sharding ดังนั้นในบางกรณีฉันต้องมีกรอบงานเอนทิตี้เพื่อเชื่อมต่อกับฐานข้อมูลที่แตกต่างกัน (ของโครงสร้างเดียวกัน) ฉันเข้าใจคุณอย่างถูกต้องหรือไม่
แมทธิว

จากรหัสที่คุณระบุดูเหมือนว่าคุณไม่ได้ทำ DI เลย วัตถุประสงค์หลักของ DI คือการทำให้คุณและรหัสของคุณปลอดจากการจัดการการพึ่งพา ฉันไม่สามารถจินตนาการว่าคุณทำมันเองอย่างมีประสิทธิภาพหากไม่มี DI container
Boris Yankov

ยังเปิดใจด้วย DI ฉันสนุกแล้วได้ถามคำถามเดียวกันกับที่นี่ในฟอรัมอื่นเพื่อรับคำตอบที่ตรงข้ามกัน DI เป็นรูปแบบไม่ใช่สถาปัตยกรรม ขึ้นอยู่กับวัตถุประสงค์ของคุณคุณสามารถตัดสินใจที่จะใช้หรือไม่ ฉันใช้มัน แต่ไม่ใช่ด้วยเหตุผลที่คนส่วนใหญ่บอกให้ฉันใช้
Bastien Vandamme

4

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

วิธีนี้ไม่จำเป็นต้องเป็นฐานข้อมูลที่ใช้ที่เก็บของคุณ พวกเขาอาจเป็นหน่วยความจำแคชหรืออะไรก็ได้ บางทีคุณอาจใช้กรอบการฉีดแบบพึ่งพาเพื่อสร้างอินสแตนซ์เหล่านี้ได้

ดังนั้นเพื่อตอบคำถามของคุณ:

  1. ใช่ฉันคิดว่ามันโอเค
  2. ฉันยังคงมี UI อ้างอิงโครงการ EF และอินเทอร์เฟซการอ้างอิงเลเยอร์ธุรกิจที่ชั้นเก็บข้อมูลของ EF ใช้ ด้วยวิธีนี้โครงการอื่น ๆ ยังคงสามารถใช้ชุดประกอบเดียวกันได้ แต่พวกเขามีความยืดหยุ่นในการแลกเปลี่ยนหากต้องการ
  3. อืมอาจเป็นที่เก็บในเลเยอร์การเข้าถึง แต่การใช้นิยามอินเตอร์เฟสที่เปิดเผยในเลเยอร์ธุรกิจ

นี่เป็นเพียงความคิดที่จะครุ่นคิด


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