Tôi có nên sử dụng kho lưu trữ trong Đối tượng miền hoặc đẩy Đối tượng miền trở lại Lớp dịch vụ?


11

Tôi đã đến từ một thế giới kịch bản giao dịch và tôi mới bắt đầu xem xét DDD. Tôi không chắc chắn về cách chính xác để tích hợp thiết kế DDD với sự kiên trì của cơ sở dữ liệu. Đây là những gì tôi có:

Một lớp dịch vụ có tên OrganisationService có giao diện chứa các phương thức để truy xuất và lưu các thể hiện của các đối tượng miền Tổ chức. Tổ chức là một gốc tổng hợp và có dữ liệu khác liên quan đến nó: Thành viên và Giấy phép. Cơ sở dữ liệu EF6 DBContext đầu tiên được sử dụng trong OrganisationService để truy xuất các thực thể OrganisationDB và các thực thể MemberDB và LicenseDB có liên quan. Tất cả đều được chuyển đổi thành tương đương lớp đối tượng miền của họ khi được OrganisationService truy xuất và được tải vào đối tượng miền Tổ chức. Đối tượng này trông giống như vậy:

public class Organisation
{
    public IList<Member> Members { get; set; }
    public IList<License> Licenses { get; set; }
}

Tôi hiện không sử dụng mẫu Kho lưu trữ trong Tổ chức dịch vụ ... Tôi đang sử dụng chính EF làm Kho lưu trữ vì có vẻ như hiện tại, EF6 đã khiến kho lưu trữ trở nên dư thừa.

Tại thời điểm này trong thiết kế, đối tượng miền Tổ chức bị thiếu máu: nó trông giống như lớp Tổ chức EF POCO. Lớp OrganisationService trông rất giống Kho lưu trữ!

Bây giờ tôi cần bắt đầu thêm logic. Logic này bao gồm quản lý một giấy phép tổ chức và thành viên. Bây giờ trong tập lệnh giao dịch, tôi sẽ thêm các phương thức vào OrganisationService để xử lý các hoạt động này và gọi vào Kho lưu trữ để tương tác với DB, nhưng với DDD tôi tin rằng logic này nên được gói gọn trong chính đối tượng miền Tổ chức ...

Đây là nơi tôi không chắc chắn về những gì tôi nên làm: Tôi sẽ cần phải duy trì dữ liệu này trở lại cơ sở dữ liệu như là một phần của logic. Điều này có nghĩa là tôi nên sử dụng DbContext trong đối tượng miền Tổ chức để làm điều này? Là sử dụng kho lưu trữ / EF trong đối tượng tên miền thực hành xấu? Nếu vậy, sự kiên trì này thuộc về đâu?

public class Organisation
{
    public IList<Member> Members { get; set; }
    public IList<License> Licenses { get; set; }

    public void AddLicensesToOrganisation(IList<License> licensesToAdd)
    {
        // Do validation/other stuff/

        // And now Save to the DB???
        using(var context = new EFContext())
        {
            context.Licenses.Add(...
        }

        // Add to the Licenses collection in Memory
        Licenses.AddRange(licensesToAdd);
    }
}

Thay vào đó tôi có nên thay đổi đối tượng miền Tổ chức trong bộ nhớ và sau đó đẩy nó trở lại OrganisationService để duy trì không? Sau đó, tôi phải theo dõi những gì thực sự thay đổi trên đối tượng (đó là những gì EF làm với POCO của chính nó! Tôi cảm thấy rằng EF không chỉ là một kho lưu trữ thay thế, mà còn có thể là lớp miền!)

Bất kỳ hướng dẫn ở đây được đánh giá cao.

Câu trả lời:


2

Bạn có thể thực hiện một trong hai cách tiếp cận và làm cho nó hoạt động tốt - tất nhiên, có những ưu và nhược điểm.

Entity Framework chắc chắn có ý định làm nghẹt các thực thể miền của bạn. Nó hoạt động tốt khi các thực thể miền và thực thể dữ liệu của bạn là cùng một lớp. Sẽ tốt hơn nhiều nếu bạn có thể dựa vào EF để theo dõi các thay đổi cho bạn và chỉ gọi context.SaveChanges()khi bạn hoàn thành công việc giao dịch của mình. Điều đó cũng có nghĩa là các thuộc tính xác thực của bạn không phải được đặt hai lần, một lần trên các mô hình miền của bạn và một lần trên các thực thể bền vững của bạn - những thứ như [Required]hoặc [StringLength(x)]có thể được kiểm tra trong logic nghiệp vụ của bạn , cho phép bạn bắt trạng thái dữ liệu không hợp lệ trước khi bạn cố gắng thực hiện giao dịch DB và nhận được mộtEntityValidationException. Cuối cùng, mã hóa nhanh chóng - bạn không cần phải viết một lớp ánh xạ hoặc kho lưu trữ, mà thay vào đó có thể làm việc trực tiếp với bối cảnh EF. Nó đã là một kho lưu trữ và một đơn vị công việc, vì vậy các lớp trừu tượng thêm không hoàn thành bất cứ điều gì.

Một nhược điểm của việc kết hợp tên miền của bạn và các thực thể bền bỉ là bạn kết thúc với một loạt các [NotMapped]thuộc tính nằm rải rác trong các thuộc tính của bạn. Thông thường, bạn sẽ muốn các thuộc tính dành riêng cho tên miền là các bộ lọc chỉ nhận được trên dữ liệu được duy trì hoặc được đặt sau trong logic nghiệp vụ của bạn và không được lưu lại vào cơ sở dữ liệu của bạn. Đôi khi, bạn sẽ muốn thể hiện dữ liệu của mình trong các mô hình miền của mình theo cách không hoạt động tốt với cơ sở dữ liệu - ví dụ: khi sử dụng enums, Entity sẽ ánh xạ các dữ liệu này vào một intcột - nhưng có lẽ bạn muốn ánh xạ chúng có thể đọc được bằng con người string, vì vậy bạn không cần tham khảo tra cứu khi kiểm tra cơ sở dữ liệu. Sau đó, bạn kết thúc với một stringtài sản được ánh xạ, mộtenumthuộc tính không (nhưng lấy chuỗi và ánh xạ tới enum) và API hiển thị cả hai! Tương tự, nếu bạn muốn kết hợp các loại (bảng) phức tạp trên các bối cảnh, bạn có thể kết thúc với mappedOtherTableId và một thuộc tính chưa được ánh xạ ComplexType, cả hai đều được hiển thị dưới dạng công khai trên lớp của bạn. Điều này có thể gây nhầm lẫn cho một người không quen thuộc với dự án và làm phình to các mô hình miền của bạn một cách không cần thiết.

Logic / tên miền kinh doanh của tôi càng phức tạp, tôi càng thấy hạn chế hoặc cồng kềnh khi kết hợp tên miền của mình và các thực thể bền bỉ. Đối với các dự án có thời hạn ngắn hoặc không thể hiện một lớp kinh doanh phức tạp, tôi cảm thấy rằng việc sử dụng các thực thể EF cho cả hai mục đích là phù hợp và không cần phải trừu tượng hóa tên miền của bạn khỏi sự kiên trì của bạn. Đối với các dự án cần mở rộng dễ dàng tối đa hoặc cần thể hiện logic rất phức tạp, tôi nghĩ rằng tốt hơn hết bạn nên tách hai và xử lý sự phức tạp kéo dài thêm.

Một mẹo để tránh sự cố theo dõi thủ công các thay đổi thực thể của bạn là lưu trữ ID thực thể tồn tại tương ứng trong mô hình miền của bạn. Điều này có thể được điền tự động bởi lớp ánh xạ của bạn. Sau đó, khi bạn cần duy trì thay đổi trở lại EF, hãy truy xuất thực thể liên tục liên quan trước khi thực hiện bất kỳ ánh xạ nào. Sau đó, khi bạn ánh xạ các thay đổi, EF sẽ tự động phát hiện chúng và bạn có thể gọi context.SaveChanges()mà không cần phải theo dõi chúng bằng tay.

public class OrganisationService
{
    public void PersistLicenses(IList<DomainLicenses> licenses) 
    {
        using (var context = new EFContext()) 
        {
            foreach (DomainLicense license in licenses) 
            {
                var persistedLicense = context.Licenses.Find(pl => pl.Id == license.PersistedId);
                MappingService.Map(persistedLicense, license); //Right-left mapping
                context.Update(persistedLicense);
            }
            context.SaveChanges();
        }
    }
}

Có vấn đề gì khi kết hợp các cách tiếp cận khác nhau với độ phức tạp khác nhau của dữ liệu không? nếu bạn có thứ gì đó ánh xạ độc đáo tới DB, chỉ cần sử dụng trực tiếp EF. Nếu bạn có thứ gì đó không có, thì hãy giới thiệu ánh xạ / trừu tượng trước khi sử dụng EF.
Euphoric

@Euphoric sự khác biệt của miền và db có thể được xử lý trong ánh xạ. Tôi không thể nghĩ đến trường hợp sử dụng khi thêm tên miền hai lần (không liên tục và liên tục) và xử lý theo dõi thay đổi bằng tay sẽ ít hiệu quả hơn so với việc thêm ánh xạ cho các trường hợp đặc biệt. Bạn có thể chỉ cho tôi một? (Tôi giả sử sử dụng NHibernate, có lẽ EF bị hạn chế hơn?)
Firo

Rất hữu ích, thực tế và thông tin trả lời. Đánh dấu là câu trả lời. Cảm ơn!
MrLane

3

Tôi không biết EF6 nhưng các ORM khác xử lý việc này một cách minh bạch để bạn không phải thêm giấy phép vào ngữ cảnh một cách rõ ràng, nó sẽ phát hiện ra chúng khi lưu các thay đổi. Vì vậy, phương pháp sẽ xuống

public void AddLicenses(IEnumerable<License> licensesToAdd)
{
    // Do validation/other stuff/
    // Add to the Licenses collection in Memory
    Licenses.AddRange(licensesToAdd);
}

và mã xung quanh nó

var someOrg = Load(orgId);

someOrg.AddLicenses(someLicences);

SaveChanges();

Các đối tượng miền của tôi không phải là Thực thể, vì vậy việc thêm chúng vào bộ sưu tập Giấy phép, chỉ là Danh sách sẽ không cắt giảm. Câu hỏi không phải là quá nhiều về EF mặc dù đó là nơi mà sự kiên trì thực sự diễn ra. Tất cả sự kiên trì trong EF phải diễn ra trong phạm vi bối cảnh. Câu hỏi là cái này thuộc về đâu?
MrLane

2
các thực thể miền và các thực thể bền vững có thể / nên giống nhau nếu không bạn giới thiệu một lớp trừu tượng khác mà 99% thời gian không thêm giá trị và theo dõi thay đổi bị mất.
Firo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.