ฉันเป็นพื้นที่เก็บข้อมูลแม้ว่าฉันจะย้ายออกจากรูปแบบพื้นที่เก็บข้อมูลทั่วไป ฉันจัดตำแหน่งที่เก็บของฉันกับฟังก์ชันธุรกิจที่พวกเขาให้บริการแทน ที่เก็บไม่ได้มุ่งเป้าไปที่การแยกเก็บออมออกไปเพราะนี่ไม่ใช่สิ่งที่ฉันคาดหวังว่าจะเปลี่ยนออกและในเวลาเดียวกันฉันก็หลีกเลี่ยงการสร้างที่เก็บข้อมูลที่ละเอียดเกินไป (Ie CRUD) แทนที่เก็บของฉันมีวัตถุประสงค์หลักสองถึงสาม:
- การดึงข้อมูล
- การสร้างข้อมูล
- การลบอย่างหนัก
IQueryable<TEntity>
สำหรับการเรียกใช้ข้อมูลที่เก็บผลตอบแทนเสมอ สำหรับการสร้างข้อมูลจะส่งคืน TEntity ที่เก็บจัดการการกรองระดับพื้นฐานของฉันเช่นการอนุญาตสถานะ "แอ็คทีฟ" สำหรับระบบที่ใช้รูปแบบการลบแบบอ่อนและสถานะ "ปัจจุบัน" สำหรับระบบที่ใช้ข้อมูลประวัติ การสร้างข้อมูลมีความรับผิดชอบเพียงเพื่อให้มั่นใจว่าการอ้างอิงที่ต้องการได้รับการแก้ไขและเชื่อมโยงและมีการตั้งค่าเอนทิตีและพร้อมใช้งาน
การอัปเดตข้อมูลเป็นความรับผิดชอบของตรรกะทางธุรกิจที่ทำงานกับเอนทิตีที่มีปัญหา ซึ่งอาจรวมถึงสิ่งต่าง ๆ เช่นกฎการตรวจสอบ ฉันไม่ลอง encapsulating ในวิธีการเก็บข้อมูล
การลบในระบบส่วนใหญ่ของฉันคือการลบแบบอ่อนดังนั้นมันจะอยู่ภายใต้การปรับปรุงข้อมูล (IsActive = false) ในกรณีของการลบยากนี่จะเป็นหนึ่งซับในที่เก็บ
ทำไมต้องเป็นที่เก็บ ทดสอบความสามารถ แน่นอนว่า DbContext สามารถถูกเยาะเย้ยได้ แต่จะง่ายกว่าถ้าเยาะเย้ยคลาสที่คืนค่าIQueryable<TEntity>
. พวกเขายังเล่นได้ดีกับรูปแบบ UoW โดยส่วนตัวแล้วฉันใช้รูปแบบ DbContextScope ของ Mehdime เพื่อกำหนดขอบเขตของหน่วยงานในระดับที่ฉันต้องการ (Ie Controllers ใน MVC) และให้ผู้ควบคุมและผู้ให้บริการชั้นเรียนใช้ที่เก็บข้อมูลโดยไม่ต้องผ่านการอ้างอิง UoW / dbContext รอบ ๆ การใช้ IQueryable หมายความว่าคุณไม่จำเป็นต้องใช้วิธีการห่อหุ้มจำนวนมากในที่เก็บและรหัสของคุณสามารถปรับวิธีการใช้ข้อมูลให้เหมาะสม ตัวอย่างเช่นพื้นที่เก็บข้อมูลไม่จำเป็นต้องเปิดเผยวิธีการเช่น "มีอยู่" หรือ "นับ" หรือพยายามห่อเอนทิตีกับ POCO อื่น ๆ ในกรณีที่คุณต้องการชุดข้อมูลย่อย พวกเขาไม่จำเป็นต้องจัดการกับตัวเลือกการโหลดกระตือรือร้นสำหรับข้อมูลที่เกี่ยวข้องที่คุณอาจหรืออาจไม่จำเป็น โดยผ่าน IQueryable รหัสการโทรสามารถ:
.Any()
.Count()
.Include() // Generally avoided, instead I use .Select()
.Where()
.Select(x => new ViewModel or Anon. Type)
.Skip().Take()
.FirstOrDefault() / .SingleOrDefault() / .ToList()
มีความยืดหยุ่นสูงและจากการทดสอบ PoV ที่เก็บจำลองของฉันเพียงต้องการส่งคืนรายการของวัตถุเอนทิตีที่มีประชากร
สำหรับที่เก็บทั่วไปฉันได้ย้ายออกไปจากที่นี่เป็นส่วนใหญ่เพราะเมื่อคุณจบลงด้วยที่เก็บต่อตารางตัวควบคุม / บริการของคุณจบลงด้วยการอ้างอิงไปยังที่เก็บหลายแห่งเพื่อดำเนินการทางธุรกิจเดียว ในกรณีส่วนใหญ่ที่เก็บข้อมูลเหล่านี้เพียงหนึ่งหรือสองแห่งกำลังดำเนินการเขียนจริง (หากคุณใช้คุณสมบัติการนำทางอย่างเหมาะสม) ในขณะที่ที่เหลือรองรับการอ่านด้วย ฉันอยากมีบางสิ่งบางอย่างเช่น OrdersRepository ที่สามารถอ่านและสร้างคำสั่งซื้อและอ่านการค้นหาที่เกี่ยวข้องอื่น ๆ (วัตถุลูกค้าที่มีน้ำหนักเบาผลิตภัณฑ์ ฯลฯ ) เพื่ออ้างอิงเมื่อสร้างคำสั่งซื้อแทนที่จะตี 5 หรือ 6 ที่เก็บที่แตกต่างกัน มันอาจละเมิด DNRY purists แต่ข้อโต้แย้งของฉันคือว่าวัตถุประสงค์ของที่เก็บคือเพื่อให้บริการการสร้างคำสั่งซื้อซึ่งรวมถึงการอ้างอิงที่เกี่ยวข้องRepository<Product>
เพื่อให้ได้ผลิตภัณฑ์โดยใช้พื้นฐานของคำสั่งซื้อฉันจะต้องมีเอนทิตีที่มีฟิลด์จำนวนหนึ่งเท่านั้น OrderRepository ของฉันอาจมี.GetProducts()
วิธีการส่งคืนIQueryable<ProductSummary>
ซึ่งฉันพบว่าดีกว่าRepository<Product>
ที่มีวิธี "รับ" หลายวิธีเพื่อลองและให้บริการพื้นที่ต่าง ๆ ตามความต้องการของแอปพลิเคชันและ / หรือนิพจน์การกรองแบบพาส - อินที่ซับซ้อน
ฉันเลือกใช้รหัสที่ง่ายกว่าซึ่งง่ายต่อการติดตามทดสอบและปรับแต่ง มันสามารถถูกทารุณกรรมในรูปแบบที่ไม่ดี แต่ฉันอยากจะมีบางสิ่งที่การละเมิดนั้นง่ายต่อการตรวจจับและแก้ไขมากกว่าพยายาม "ล็อค" รหัสในวิธีที่ไม่สามารถถูกทารุณกรรมล้มเหลวแล้วก็มีบางอย่างที่ ฝันร้ายที่จะต้องทำสิ่งที่ลูกค้าจ่ายไปให้ได้ในที่สุด :)