รูปแบบพื้นที่เก็บข้อมูลเทียบกับ DAL


92

พวกเดียวกันหรือเปล่า? เพิ่งดูบทช่วยสอนหน้าร้านของ Rob Conneryเสร็จแล้วและดูเหมือนว่าพวกเขาจะคล้าย ๆ กัน ฉันหมายถึงเมื่อฉันใช้อ็อบเจกต์ DAL ฉันมีเมธอด GetStuff, Add / Delete และอื่น ๆ และฉันมักจะเขียนอินเทอร์เฟซก่อนเพื่อที่ฉันจะสามารถเปลี่ยน db ในภายหลังได้

ฉันสับสนหรือเปล่า?

คำตอบ:


88

คุณไม่ใช่คนที่ทำให้สับสน :-)

ฉันคิดว่าคำตอบของคำถามขึ้นอยู่กับว่าคุณอยากเป็นคนเจ้าระเบียบมากแค่ไหน

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

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

บางคนจะใส่ข้อ จำกัด DDD ในที่เก็บมากขึ้นในขณะที่คนอื่น ๆ จะใช้ที่เก็บเป็นสื่อกลางที่สะดวกระหว่างฐานข้อมูลและชั้นบริการ ที่เก็บเช่น DAL จะแยกชั้นบริการออกจากข้อมูลเฉพาะการเข้าถึงข้อมูล

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

public interface IRepository : IDisposable
{
    T[] GetAll<T>();
    T[] GetAll<T>(Expression<Func<T, bool>> filter);
    T GetSingle<T>(Expression<Func<T, bool>> filter);
    T GetSingle<T>(Expression<Func<T, bool>> filter, List<Expression<Func<T, object>>> subSelectors);
    void Delete<T>(T entity);
    void Add<T>(T entity);
    int SaveChanges();
    DbTransaction BeginTransaction();
}

นี่คือ DAL หรือที่เก็บ? ในกรณีนี้ฉันเดาว่ามันทั้งสองอย่าง

คิม


5
สายไปปาร์ตี้ที่นี่ แต่ทำไม T [] ไม่ใช่ List <T> (หรือคล้าย ๆ กัน)?
— Mike Kingscott

27
บางที IEnumerable <T> น่าจะดีที่สุด
— Venemo

9
หรือ IQueryable <T>
— kenwarner

1
ฉันคิดว่า IQueryable <T> น่าจะเป็นตัวเลือกที่ดีที่สุดเพราะมันช่วยให้คุณสามารถเชื่อมโยงวิธีการและเลื่อนการดำเนินการเพื่อให้ฐานข้อมูลทำงานทั้งหมดได้
— 0lukasz0

4
@kenwarner ฉันคิดว่าการคืนค่า IQueryable <T> ทำให้สิ่งที่เป็นนามธรรมรั่วไหล คุณควรส่งคืนอ็อบเจ็กต์โดเมนจากที่เก็บของคุณ
— Matthew

42

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

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


23

ความแตกต่างอย่างมากประการหนึ่งคือ DAO เป็นวิธีทั่วไปในการจัดการกับความคงอยู่ของเอนทิตีใด ๆ ในโดเมนของคุณ ในทางกลับกันที่เก็บจะเกี่ยวข้องกับรากรวมเท่านั้น


26
สิ่งแรกที่ต้องเข้าใจคือที่เก็บเป็นรูปแบบเป็นส่วนหนึ่งของระบบขนาดใหญ่ที่เรียกว่า Domain Driven Design ใน DDD ออบเจ็กต์โดเมนถูกจัดกลุ่มเป็นแบบรวมโดยแต่ละรายการจะมีรูทรวม เช่น PurchaseOrder เป็นรูทรวมและ OrderItems เป็นชายด์ภายในรูทรวม ที่เก็บจะเกี่ยวข้องกับรากรวมเท่านั้น นั่นคือตัวอย่าง OrderItem จะไม่ถูกโหลดโดยไม่ขึ้นอยู่กับว่าเป็น aggreate root ดังนั้นคุณจะไม่มีที่เก็บ OrderItem ใน DDD อย่างไรก็ตามในระบบที่ไม่ใช่ DDD คุณสามารถมี OrderItemDao ได้เนื่องจาก Dao ไม่ได้ จำกัด เฉพาะรากรวม
— ไตร่ตรอง

NG ขอบคุณ! ฉันเริ่มเห็นแบบนั้นแล้ว แต่สิ่งนี้ทำให้ชัดเจน ฉันจะต้องเริ่มอ่านวรรณกรรม DDD ทั้งหมด!
— เดวิด

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

12

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

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

ฉันอาจจะไปไกลแล้วและระบุว่าเว้นแต่จะใช้รูปแบบพื้นที่เก็บข้อมูลร่วมกับรูปแบบข้อมูลจำเพาะไม่ใช่ "Repository" แต่เป็น DAL ตัวอย่างที่สร้างขึ้นในรหัสหลอก:

specification100 = new AccountHasMoreOrdersThan(100)
specification200 = new AccountHasMoreOrdersThan(200)

assert that specification200.isSpecialCaseOf(specification100)

specificationAge = new AccountIsOlderThan('2000-01-01')

combinedSpec = new CompositeSpecification(
    SpecificationOperator.And, specification200, specificationAge)

for each account in Repository<Account>.GetAllSatisfying(combinedSpec)
    assert that account.Created < '2000-01-01'
    assert that account.Orders.Count > 200

ดูรายละเอียดของ Fowler's Specification Essay (นั่นคือสิ่งที่ฉันอ้างอิงจากข้างต้น)

DAL จะมีวิธีการพิเศษเช่น

IoCManager.InstanceFor<IAccountDAO>()
    .GetAccountsWithAtLeastOrdersAndCreatedBefore(200, '2000-01-01')

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

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


2

ความเห็นส่วนตัวของฉันก็คือว่ามันคือทั้งหมดที่เกี่ยวกับการทำแผนที่ดู: http://www.martinfowler.com/eaaCatalog/repository.html ดังนั้นเอาต์พุต / อินพุตจากที่เก็บจึงเป็นอ็อบเจ็กต์โดเมนซึ่งบน DAL อาจเป็นอะไรก็ได้ สำหรับฉันนั่นคือการเพิ่ม / ข้อ จำกัด ที่สำคัญเนื่องจากคุณสามารถเพิ่มการใช้งานที่เก็บสำหรับฐานข้อมูล / บริการ / อะไรก็ตามที่มีเลย์เอาต์ที่แตกต่างกันและคุณมีจุดที่ชัดเจนในการทำแผนที่ หากคุณไม่ได้ใช้ข้อ จำกัด นั้นและมีการทำแผนที่ที่อื่นการมีวิธีต่างๆในการแสดงข้อมูลอาจส่งผลต่อรหัสในที่ที่ไม่ควรเปลี่ยนแปลง


1

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


1

ในที่เก็บโลกภายนอก (เช่นรหัสไคลเอนต์) จะเหมือนกับ DAL ยกเว้น:

(1) วิธีการแทรก / อัปเดต / ลบถูก จำกัด ให้มีวัตถุที่เก็บข้อมูลเป็นพารามิเตอร์

(2) สำหรับการดำเนินการอ่านอาจใช้ข้อกำหนดง่ายๆเช่น DAL (เช่น GetByPK) หรือข้อกำหนดขั้นสูง

ภายในทำงานร่วมกับ Data Mapper Layer (เช่นบริบทของกรอบงานเอนทิตีเป็นต้น) เพื่อดำเนินการ CRUD จริง

รูปแบบพื้นที่เก็บข้อมูลไม่ได้หมายถึงอะไร: -

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

หวังว่านี่จะช่วยได้!


1

Repository เป็นรูปแบบซึ่งเป็นวิธีการนำสิ่งต่าง ๆ ไปใช้ในรูปแบบมาตรฐานเพื่อนำโค้ดกลับมาใช้ใหม่เท่าที่เราทำได้


1

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


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

0

จากสิ่งที่ฉันเข้าใจพวกเขาอาจหมายถึงสิ่งเดียวกันโดยพื้นฐาน - แต่การตั้งชื่อจะแตกต่างกันไปตามบริบท

ตัวอย่างเช่นคุณอาจมีคลาส Dal / Dao ที่ใช้อินเทอร์เฟซ IRepository

Dal / Dao เป็นคำศัพท์ชั้นข้อมูล ระดับที่สูงขึ้นของแอปพลิเคชันของคุณจะคิดในแง่ของที่เก็บ


0

ดังนั้นในกรณีส่วนใหญ่ (ง่าย ๆ ) DAO คือการนำ Repository มาใช้?

เท่าที่ฉันเข้าใจดูเหมือนว่า DAO จะเกี่ยวข้องกับการเข้าถึงฐานข้อมูลอย่างแม่นยำ (CRUD - ไม่มีการเลือกแม้ว่า?!) ในขณะที่ Repository ช่วยให้คุณสามารถสรุปการเข้าถึงข้อมูลทั้งหมดได้โดยอาจเป็นส่วนหน้าของ DAO หลายตัว (อาจเป็นแหล่งข้อมูลที่แตกต่างกัน)

ฉันมาถูกทางหรือเปล่า


อันที่จริงฉันจะย้อนกลับและบอกว่าจากมุมมองที่เรียบง่าย Repository เป็นรูปแบบการใช้งานเฉพาะสำหรับ DAO แต่ใช่คุณมาถูกทางแล้ว (R จาก CRUD = อ่านดังนั้นนั่นคือสิ่งที่คุณเลือก)
— Jeromy Irvine

0

อาจโต้แย้งได้ว่า "ที่เก็บ" เป็นคลาสเฉพาะและ "DAL" คือเลเยอร์ทั้งหมดที่ประกอบด้วยที่เก็บ DTO คลาสยูทิลิตี้และสิ่งอื่น ๆ ที่จำเป็น

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