2009-03-16 25 views
7

Tôi dường như đã nhận được bản thân mình vào một chút nhầm lẫn của toàn bộ kinh doanh DDD \ LinqToSql này. Tôi đang xây dựng một hệ thống bằng cách sử dụng POCOS và LINQ để sql và tôi có kho cho các rễ tổng hợp. Vì vậy, ví dụ nếu bạn có các lớp Order-> OrderLine bạn có một kho chứa cho Order nhưng không OrderLine là Order là gốc của tổng hợp. Kho lưu trữ có phương pháp xóa để xóa Thứ tự, nhưng làm thế nào để bạn xóa OrderLines? Bạn có thể nghĩ rằng bạn đã có một phương thức trên Lệnh gọi là RemoveOrderLine đã xóa dòng khỏi bộ sưu tập OrderLines nhưng nó cũng cần phải xóa OrderLine khỏi bảng l2s cơ bản. Vì không có một kho lưu trữ cho OrderLine, bạn phải làm như thế nào?Thiết kế điều khiển miền (LINQ to SQL) - Làm cách nào để xóa các phần của tổng hợp?

Có thể có các kho lưu trữ công cộng chuyên biệt để truy vấn nguồn gốc và kho lưu trữ chung bên trong mà các đối tượng miền thực sự sử dụng để xóa nội dung trong tổng hợp?

public class OrderRepository : Repository<Order> { 
    public Order GetOrderByWhatever(); 
} 

public class Order { 
    public List<OrderLines> Lines {get; set;} //Will return a readonly list 
    public RemoveLine(OrderLine line) { 
     Lines.Remove(line); 
     //************* NOW WHAT? *************// 
     //(new Repository<OrderLine>(uow)).Delete(line) Perhaps?? 
     // But now we have to pass in the UOW and object is not persistent ignorant. AAGH! 
    } 
} 

Tôi rất thích biết những gì người khác đã làm như tôi không thể là người duy nhất gặp khó khăn với điều này .... Tôi hy vọng .... Cảm ơn

Trả lời

2

Bạn gọi RemoveOrderLine trên theo thứ tự mà gọi logic liên quan. Điều này không bao gồm thực hiện các thay đổi đối với phiên bản liên tục của nó.

Sau đó, bạn gọi phương thức Lưu/Cập nhật trên kho lưu trữ, sẽ nhận được thứ tự đã sửa đổi. Thử thách cụ thể trở thành khi biết những gì đã thay đổi trong đối tượng miền, có một số tùy chọn (tôi chắc chắn có nhiều tùy chọn tôi liệt kê):

  • Cho đối tượng miền theo dõi các thay đổi, sẽ bao gồm việc theo dõi rằng x cần phải được xóa khỏi các dòng lệnh. Một cái gì đó tương tự như theo dõi thực thể có thể được yếu tố ra là tốt.
  • Tải phiên bản được duy trì. Có mã trong kho lưu trữ nhận ra sự khác biệt giữa phiên bản được lưu giữ và phiên bản trong bộ nhớ và chạy các thay đổi.
  • Tải phiên bản được duy trì. Có mã trong tổng hợp gốc, mà sẽ cho bạn sự khác biệt cho một tổng hợp gốc ban đầu.
+0

Tôi cho rằng sự mở rộng này có nghĩa là bạn không sử dụng ORM trực tiếp trên các thực thể miền của bạn. Tôi đã hy vọng để có thể tránh được công việc thêm bạn mô tả ở trên, bằng cách có linq để sql tự động tồn tại những thay đổi tôi thực hiện đối tượng tên miền ... –

+0

y, đó là vấn đề thực sự. Tôi đã làm như trên. Tôi thường xuyên thấy bình luận trên Nhibernate hỗ trợ nhiều kịch bản nâng cao hơn, nhưng tôi chưa xem xét cách chơi với kiểu kịch bản này (không chỉ sử dụng POCO) – eglasius

+0

Cảm ơn bạn; mặc dù không phải là lý tưởng khủng khiếp (lỗi của LTS, không phải câu trả lời của bạn) điều này dường như để xác nhận linh cảm của riêng tôi về cách tôi cần phải làm điều này ... – Funka

1

Trước tiên, bạn nên để lộ giao diện để có được tham chiếu đến Tổng hợp gốc của bạn (ví dụ: Order()). Sử dụng mẫu Nhà máy để tạo mới một phiên bản mới của Tổng hợp gốc (ví dụ: Order()).

Với điều đó đã nói, các phương pháp trên các đối tượng Tổng hợp gốc của bạn truy cập vào các đối tượng liên quan - không phải chính nó. Ngoài ra, không bao giờ để lộ một loại phức tạp như công khai trên các gốc tổng hợp (nghĩa là bộ sưu tập IList của dòng() mà bạn đã nêu trong ví dụ). Điều này vi phạm pháp luật của decremeter (sp ck), mà nói rằng bạn không thể "Dot Walk" theo cách của bạn để phương pháp, chẳng hạn như Order.Lines.Add().

Và ngoài ra, bạn vi phạm quy tắc cho phép khách hàng truy cập tham chiếu đến đối tượng nội bộ trên Tổng hợp gốc. Các rễ tổng hợp có thể trả về một tham chiếu của một đối tượng bên trong. Miễn là, máy khách bên ngoài không được phép giữ một tham chiếu đến đối tượng đó. Tức là, "OrderLine" của bạn, bạn chuyển vào RemoveLine(). Bạn không thể cho phép khách hàng bên ngoài kiểm soát trạng thái nội bộ của mô hình của bạn (ví dụ: Order() và OrderLines()). Do đó, bạn nên mong đợi OrderLine là một cá thể mới để hành động theo đó.

public interface IOrderRepository 
{ 
    Order GetOrderByWhatever(); 
} 

internal interface IOrderLineRepository 
{ 
    OrderLines GetOrderLines(); 
    void RemoveOrderLine(OrderLine line); 
} 

public class Order 
{ 
    private IOrderRepository orderRepository; 
    private IOrderLineRepository orderLineRepository; 
    internal Order() 
    { 
    // constructors should be not be exposed in your model. 
    // Use the Factory method to construct your complex Aggregate 
    // Roots. And/or use a container factory, like Castle Windsor 
    orderRepository = 
      ComponentFactory.GetInstanceOf<IOrderRepository>(); 
    orderLineRepository = 
      ComponentFactory.GetInstanceOf<IOrderLineRepository>(); 
    } 
    // you are allowed to expose this Lines property within your domain. 
    internal IList<OrderLines> Lines { get; set; } 
    public RemoveOrderLine(OrderLine line) 
    { 
    if (this.Lines.Exists(line)) 
    { 
     orderLineRepository.RemoveOrderLine(line); 
    } 
    } 
} 

Đừng quên nhà máy của bạn để tạo ra các trường hợp mới của Dòng():

public class OrderFactory 
{ 
    public Order CreateComponent(Type type) 
    { 
    // Create your new Order.Lines() here, if need be. 
    // Then, create an instance of your Order() type. 
    } 
} 

khách hàng bên ngoài của bạn không có quyền truy cập vào IOrderLinesRepository trực tiếp, thông qua giao diện để có được một tài liệu tham khảo của đối tượng giá trị trong Gốc tổng hợp của bạn. Nhưng, tôi cố gắng ngăn chặn điều đó bằng cách buộc tất cả các tham chiếu của tôi bị loại khỏi các phương thức của Tổng hợp. Vì vậy, bạn có thể đánh dấu IOrderLineRepository ở trên là nội bộ để nó không bị lộ ra.

Tôi thực sự nhóm tất cả các sáng tạo Tổng hợp của tôi vào nhiều Nhà máy. Tôi không thích cách tiếp cận của, "Một số rễ tổng hợp sẽ có các nhà máy cho các loại phức tạp, những người khác sẽ không". Dễ dàng hơn nhiều để có cùng một logic theo sau trong suốt mô hình miền. "Ồ, do đó, Sales() là một gốc tổng hợp như Order(). Phải có một nhà máy cho nó quá." Một lưu ý cuối cùng là nếu có sự kết hợp, tức là SalesOrder(), sử dụng hai mô hình Bán hàng() và Order(), bạn sẽ sử dụng một Dịch vụ để tạo và hành động trên trường hợp đó của SalesOrder() như không phải là Roots() hoặc Order() tổng hợp Roots, cũng không phải kho hoặc nhà máy của họ, tự kiểm soát thực thể SalesOrder().

Tôi đánh giá cao, khuyên bạn nên this free book bởi Abel Avram và Floyd Marinescu trên Thiết kế Drive Domain (DDD) vì nó trực tiếp trả lời câu hỏi của bạn, trong bản in khổ lớn 100 trang. Cùng với cách tách nhiều thực thể miền của bạn thành các mô-đun và như vậy.

Edit: thêm mã hơn

+0

Cảm ơn bạn đã phản hồi.Tôi không chắc chắn tuy nhiên về việc có hành vi của một dòng lệnh tiếp xúc thông qua các phương pháp trên đơn đặt hàng. Có vẻ như GetOrderLineVatAmount nên được trên đường dây nếu không bạn phải vượt qua dòng vào chức năng theo thứ tự. Ngoài ra, tại sao Order sẽ có một ref để OrderRepos? –

+0

Tất cả phụ thuộc vào cách bạn nhìn thấy "Dòng đặt hàng". Đoạn mã trên phản ánh cách tiếp cận "Đối tượng giá trị". Một đối tượng giá trị khác với một thực thể theo cách mà nó không có một danh tính. Mỗi OrderLine có một bản sắc? Nếu có, có thực sự nếu bạn nghĩ về nó? – eduncan911

+0

OrderLine.LineNumber OrderLine.Description OrderLine.Cost OrderLine.PartNumber Định nghĩa của một đối tượng giá trị ở đây không có trong danh tính; nhưng, tổng kết các giá trị của nó. Nhưng như tôi đã lưu ý ở trên trong câu trả lời, bạn có thể trưng ra IOrderLineRepository() và máy khách từ xa của bạn không có quyền truy cập. – eduncan911

0

Là một theo dõi .... tôi đã chuyển sang dùng nhibernate (chứ không phải là liên kết đến sql) nhưng trên thực tế bạn không cần phải Repos cho Hang. Nếu bạn chỉ cần loại bỏ OrderLine khỏi bộ sưu tập theo thứ tự nó sẽ chỉ xóa OrderLine từ cơ sở dữ liệu (giả sử bạn đã thực hiện ánh xạ chính xác). Khi tôi đang hoán đổi với các kho lưu trữ trong bộ nhớ, nếu bạn muốn tìm kiếm một dòng lệnh cụ thể (không biết cha mẹ thứ tự), bạn có thể viết một LINQ vào truy vấn nhibernate liên kết thứ tự với thứ tự orderlineid = giá trị. Bằng cách đó nó hoạt động khi truy vấn từ db và từ trong bộ nhớ. Vâng, bạn có ...

+0

Rất tiếc, Tôi đã thực sự hy vọng một người nào đó đã có một câu trả lời tốt hơn cho câu hỏi của bạn (rất tuyệt vời, và rất thích hợp!), Mà không cần phải từ bỏ Linq để Sql để làm điều đó! – Funka

1

Sau khi đấu tranh với vấn đề chính xác này, tôi đã tìm thấy giải pháp. Sau khi nhìn vào những gì nhà thiết kế tạo ra với l2sl, tôi nhận ra rằng giải pháp là trong các liên kết hai chiều giữa thứ tự và thứ tự. Đơn đặt hàng có nhiều đơn đặt hàng và đơn đặt hàng có một đơn hàng. Giải pháp là sử dụng các liên kết hai chiều và thuộc tính ánh xạ được gọi là DeleteOnNull (bạn có thể google để biết thông tin đầy đủ). Điều cuối cùng tôi đã bỏ lỡ là lớp thực thể của bạn cần phải đăng ký cho Thêm và loại bỏ các sự kiện từ thực thể l2s. Trong các trình xử lý này, bạn phải đặt liên kết Đơn đặt hàng trên dòng đơn đặt hàng là rỗng. Bạn có thể thấy một ví dụ về điều này nếu bạn nhìn vào một số mã mà nhà thiết kế l2s tạo ra.

Tôi biết đây là một điều bực bội, nhưng sau nhiều ngày đấu tranh với nó, tôi đã làm việc đó.

Các vấn đề liên quan