รูปแบบพื้นที่เก็บข้อมูลเทียบกับ 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.