แหล่งเก็บข้อมูลทั่วไปด้วย EF 4.1 ประเด็นคืออะไร


145

เมื่อฉันขุดลึกลงไปใน DbContext, DbSet และอินเทอร์เฟซที่เกี่ยวข้องฉันสงสัยว่าทำไมคุณต้องใช้พื้นที่เก็บข้อมูล "Generic" แยกต่างหากรอบ ๆ การใช้งานเหล่านี้?

ดูเหมือนว่า DbContext และ IDbSet จะทำทุกสิ่งที่คุณต้องการและรวมถึง "หน่วยงาน" ใน DbContext

ฉันขาดอะไรบางอย่างที่นี่หรือดูเหมือนว่าผู้คนจะเพลิดเพลินกับการเพิ่มการพึ่งพาอีกชั้นหนึ่งโดยไม่มีเหตุผล


ปัญหานี้เป็นปัญหาที่เกิดจากความเห็น / บิต ฉันได้กล่าวนี้ที่นี่
Amit Joshi

คำตอบ:


202

คุณพูดถูกจริงๆ DbContextเป็นการใช้งานของหน่วยของรูปแบบการทำงานและIDbSetเป็นการใช้รูปแบบที่เก็บ

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

เหตุผลหลักสำหรับการใช้พื้นที่เก็บข้อมูลมักจะ:

  • ซ่อน EF จากชั้นบน
  • ทำให้โค้ดทดสอบได้ดีขึ้น

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

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

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

ฉันทำตามบล็อกของ Ayende หากคุณเคยใช้ NHibernate คุณอาจรู้จักบทความของเขา ผู้ชายคนนี้เพิ่งเขียนบทความหลายฉบับเพื่อต่อต้านการใช้ที่เก็บกับ NHibernate แต่ NHibernate นั้นเยาะเย้ยได้ดีกว่ามาก


3
คุณสามารถเยาะเย้ยIDbSetคุณยังสามารถกำหนดอินเทอร์เฟซที่กำหนดเองในบริบทที่ได้รับ แต่นั่นคือทั้งหมด เมื่อรหัสของคุณใช้ ChangeTracker รายการหรือสิ่งอื่นใดมันจะต้องใช้ความพยายามอย่างมากในการห่อหุ้มทั้งหมด
Ladislav Mrnka

1
ใช่ EF ไม่ใช่เครื่องมือที่เน้นประสิทธิภาพเป็นอย่างมาก อย่างน้อย MS มีโอกาสมากมายที่จะทำให้ดีขึ้นในรุ่นอนาคต
Ladislav Mrnka

2
@chiccodoro: ถูกต้อง แต่เมื่อคลาสที่เยาะเย้ยของคุณตีแผ่IQueryableหรือยอมรับExpression<>ว่าเป็นพารามิเตอร์ซึ่งจะนำไปสู่การสอบถามภายใน Linq-to-entity คุณจะกำหนดตรรกะนอกองค์ประกอบที่เยาะเย้ยด้วยผลข้างเคียงซึ่งไม่สามารถทดสอบด้วยการทดสอบหน่วย
Ladislav Mrnka

8
ถ้าฉันใช้ DbSet และ BdContext ตรงนั้นในชั้นธุรกิจของฉันฉันต้องอ้างอิง EntityFramework.dll ที่นั่นเช่นเดียวกับในโครงการ DataLayer ของฉัน เพียงอย่างเดียวบอกฉันว่ามันจำเป็นต้องห่อบางอย่าง
Ingó Vals

2
downvote: ไม่สมบูรณ์ - การทำให้เป็นนามธรรมของ EF ที่อยู่เบื้องหลังส่วนต่อประสานที่เก็บสามารถทำให้รหัสไคลเอนต์เดียวกันทำงานใน SL และ WPF
h.alex

21

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

http://refactorthis.wordpress.com/2011/05/31/mock-faking-dbcontext-in-entity-framework-4-1-with-a-generic-repository/


5

เหตุผลหนึ่งในการสร้างที่เก็บคือคุณสามารถซ่อนการนำ DBSet และ DbContext ไปใช้หากคุณตัดสินใจย้ายจาก EntityFramework ไปเป็นอย่างอื่นหรือกลับกัน

ตัวอย่างเช่นฉันใช้ NHibernate และฉันได้รวมการเรียกไปยังเฟรมเวิร์กทั้งหมดภายในคลาสที่เก็บข้อมูล พวกเขากลับ IEnumerable สำหรับพวกเขาที่จะเป็น "ทั่วไป" และที่เก็บของฉันมีการดำเนินงาน CRUD มาตรฐาน (อัปเดตลบ ฯลฯ ) ฉันย้ายมานานจาก Entity Framework แล้ว เมื่อทำเช่นนั้นฉันไม่จำเป็นต้องเปลี่ยนอะไรในคลาส ViewModel ของฉันหรือเกินเพราะพวกเขาชี้ไปที่ที่เก็บของฉัน - ฉันเพียงแค่ต้องเปลี่ยนภายในที่เก็บของฉัน สิ่งนี้ทำให้ชีวิตง่ายขึ้นเมื่อทำการโยกย้าย

(ฉันใช้ NHibernate เพราะเรากำลังเชื่อมต่อกับ ISeries และในเวลานั้นไม่มีการใช้งานอารมณ์โดยใช้ EF กับ ISeries สิ่งเดียวที่มีให้คือจ่าย $ 12,000 ให้ IBM สำหรับ DB2Connect ของ IBM)


"เกือบ" (ในเรื่องของการซ่อน DBSet และ DbContext) คุณจะพบว่าคุณไม่จำเป็นต้องเปิดเผย EF ให้กับผู้บริโภคใด ๆ (ตัวอย่างเช่นถ้าคุณใช้ประโยชน์ DI) แต่คุณต้องการอินเทอร์เฟซที่แสดงคุณสมบัติ IDbSet <T> หรือ ไปอีกขั้นหนึ่งแล้วพิมพ์คุณสมบัติทั้งหมดของคุณเป็น IQueryable <T> แต่ประเด็นของฉันคือคุณสามารถซ่อนการพึ่งพา DbSet และ DbContext ได้อย่างสมบูรณ์ CRUD ops นั้นสามารถเขียนเป็นวิธีการขยายคุณสามารถเขียนวิธีการขยายหลายวิธีสำหรับการสำรองข้อมูลที่แตกต่างกัน อย่างไรก็ตามคุณจะไม่ซ่อนการใช้งาน LINQ
ฌอนวิลสัน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.