2010-01-19 28 views
5

Giả sử chúng tôi có một thực thể gốc tổng hợp của loại Đơn đặt hàng liên quan đến khách hàng và các dòng đơn đặt hàng. Khi tôi nghĩ về một thực thể đơn hàng, nó tự nhiên hơn khi khái niệm hóa nó như không được định nghĩa mà không có một Id. Đơn đặt hàng không có Id có vẻ được biểu thị tốt hơn dưới dạng yêu cầu đặt hàng so với đơn đặt hàng.Làm cách nào để bổ sung gốc tổng hợp vào kho lưu trữ?

Để thêm để một kho lưu trữ, tôi thường thấy người nhanh chóng trật tự mà không có Id và sau đó có kho hoàn thành các đối tượng:

class OrderRepository 
{ 
    void Add(Order order) 
    { 
     // Insert order into db and populate Id of new order 
    } 
} 

Những gì tôi thích về phương pháp này là bạn đang thêm một Ví dụ đặt hàng cho một OrderRepository. Điều đó làm cho rất nhiều ý nghĩa. Tuy nhiên, cá thể đơn đặt hàng không có một Id, và ở phạm vi của người tiêu dùng của kho lưu trữ, nó vẫn không có ý nghĩa với tôi rằng một đơn đặt hàng không có một Id. Tôi có thể định nghĩa một OrderRequest là một thể hiện của trật tự và thêm nó vào kho lưu trữ, nhưng điều đó cảm thấy giống như phát sinh một quả táo từ một quả cam và sau đó thêm nó vào một danh sách cam.

Ngoài ra, tôi cũng đã thấy phương pháp này:

class OrderRepository 
{ 
    Order AddOrder(Customer customer) 
     // It might be better to call this CreateOrder 
    { 
     // Insert record into db and return a new instance of Order 
    } 
} 

Những gì tôi thích về phương pháp này là một trật tự là undefined mà không có một Id. Kho lưu trữ có thể tạo bản ghi cơ sở dữ liệu và thu thập tất cả các trường bắt buộc trước khi tạo và trả về một thể hiện của một đơn đặt hàng. Những gì mùi ở đây là một thực tế là bạn không bao giờ thực sự thêm một thể hiện của một đơn đặt hàng vào kho lưu trữ.

Dù bằng cách nào hoạt động, vì vậy câu hỏi của tôi là: Tôi có phải sống với một trong hai cách giải thích này hay không hay nhất để mô hình hóa việc chèn?

Tôi tìm thấy câu trả lời tương tự, nhưng đối với các đối tượng giá trị: how should i add an object into a collection maintained by aggregate root. Khi nói đến một đối tượng giá trị không có sự nhầm lẫn, nhưng câu hỏi của tôi liên quan đến một thực thể có mã nhận dạng được lấy từ một nguồn bên ngoài (Id cơ sở dữ liệu được tạo tự động).

+0

Tôi cho rằng một Đơn đặt hàng không có Id không phải là một thực thể Đơn hàng, đây là nơi mà ý tưởng ban đầu đầu tiên của bạn xuất phát từ đó. Để chống lại điều này, bạn phải nhớ trạng thái của các đối tượng của bạn. Nhìn vào 'trạng thái' như là một tạm dừng trong thời gian. Tức là, một yêu cầu trang web. Trong quá trình tạo một đơn đặt hàng, có nó không có một Id lúc đầu nhưng bạn chưa hoàn thành trạng thái của nó - bạn Add() nó trong kho, do đó hoàn thành trạng thái tồn tại của Order(), mà bây giờ là hoàn thành. – eduncan911

+0

Tôi không đồng ý với bạn, tuy nhiên nếu bạn tuyên bố rằng một đơn hàng không có và Id là một thực thể cho một tạm dừng ngắn trong thời gian đó, trong thời gian tạm dừng nó sẽ không có danh tính rõ ràng. Tôi nghĩ, ít nhất là ngữ nghĩa, rằng đây là mâu thuẫn với định nghĩa của một thực thể. –

+0

Bản sắc không bị cắt và khô như bạn nghĩ. Theo đức tin của tôi, danh tính của chúng tôi là những linh hồn độc đáo của chúng tôi có mặt từ quan niệm của chúng tôi. Nhưng đối với chính phủ, danh tính của chúng tôi có thể được thiết lập thông qua nhiều phương tiện: giấy khai sinh, hộ chiếu, v.v. Có một thời điểm mà đứa trẻ không có danh tính chính thức cho chính phủ nhưng chính phủ vẫn coi đó là một thực thể, mặc dù một người cần phải xác định. Hãy suy nghĩ về một mệnh lệnh như một đứa bé quý giá và kho chứa như chính phủ (ints có nhiều người dùng thân thiện hơn!) :) – tuespetre

Trả lời

5

Tôi muốn bắt đầu bằng cách loại trừ cách tiếp cận thứ hai. Không chỉ có vẻ phản trực giác, nó cũng vi phạm một số nguyên tắc thiết kế tốt, chẳng hạn như Command-Query SeparationPrinciple of Least Surprise.

Các tùy chọn còn lại phụ thuộc vào Logic miền. Nếu miền logic mệnh lệnh rằng một thứ tự mà không có một ID là vô nghĩa, ID là một bất biến theo yêu cầu về trật tự, và chúng ta phải mô hình nó như vậy:

public class Order 
{ 
    private readonly int id; 

    public Order(int id) 
    { 
     // consider a Guard Clause here if you have constraints on the ID 
     this.id = id; 
    } 
} 

ý rằng bằng cách đánh dấu các lĩnh vực id như readonly chúng tôi đã làm cho nó một bất biến. Không có cách nào chúng ta có thể thay đổi nó cho một cá thể Order nhất định. Điều này phù hợp hoàn hảo với mẫu Thực thể của Domain-Driven Design.

Bạn có thể thực thi thêm Logic miền bằng cách đặt Điều khoản bảo vệ vào hàm tạo để ngăn ID không bị âm hoặc bằng không.

Hiện tại, bạn có thể tự hỏi làm thế nào điều này có thể hoạt động với các ID được tạo tự động từ cơ sở dữ liệu. Vâng, nó không.

Không có cách nào tốt để đảm bảo rằng ID đã cung cấp chưa được sử dụng.

Đó lá bạn với hai lựa chọn:

  • Thay đổi ID để một Guid. Điều này cho phép bất kỳ người gọi nào cung cấp ID duy nhất cho Đơn đặt hàng mới. Tuy nhiên, điều này đòi hỏi bạn phải sử dụng Guids làm khóa cơ sở dữ liệu.
  • Thay đổi API để tạo đơn đặt hàng mới không nhận đối tượng Đơn đặt hàng, mà đúng hơn là một OrderRequest như bạn đã đề xuất - OrderRequest có thể gần giống với lớp Đặt hàng, trừ ID.

Trong nhiều trường hợp, việc tạo đơn đặt hàng mới là một hoạt động kinh doanh cần mô hình cụ thể trong mọi trường hợp, vì vậy tôi thấy không có vấn đề gì về sự khác biệt này. Mặc dù OrderRequest và OrderRequest có thể rất giống nhau về mặt ngữ nghĩa, chúng thậm chí không phải liên quan đến hệ thống phân cấp kiểu.

tôi thậm chí có thể đi xa như vậy để nói rằng họ nên không thể liên quan, vì OrderRequest là một Value Object trong khi thứ tự là một Entity.

Nếu phương pháp này được thực hiện, phương thức AddOrder phải trả về một cá thể Order (hoặc ít nhất là ID), vì nếu không chúng ta không thể biết ID của thứ tự mà chúng ta vừa tạo. Điều này dẫn chúng ta trở lại vi phạm CQS đó là lý do tại sao tôi có xu hướng thích Hướng dẫn cho ID tổ chức.

+0

Câu trả lời hay! Trước khi tôi hỏi câu hỏi, tôi đang hướng tới việc thay đổi API để chấp nhận OrderRequest và tôi đồng ý với bạn rằng nó phải là một đối tượng giá trị không được bao gồm trong thứ bậc thứ tự. Tuy nhiên, bây giờ tôi thực sự thích đề xuất Guid của bạn. Tôi có thể định nghĩa một constructor Order để biết làm thế nào để tự khởi tạo nó là duy nhất, và sau đó thêm nó vào kho lưu trữ. Âm thanh hoàn hảo với tôi. Tuy nhiên tôi không thoải mái vì giải pháp này có vẻ ngoài thực hành bình thường. Bạn đã gặp phải nhiều dự án mà bạn cảm thấy thích sử dụng giải pháp này nhưng không được phép? –

+0

Bạn có thể gặp những người nghĩ rằng đây là một ý tưởng tồi vì nhiều lý do. Một số trong số đó chủ yếu liên quan đến phương pháp tiếp cận Cargo Cult với kiến ​​trúc ứng dụng, nhưng sức đề kháng vẫn có thể là thực. Nói chung, có một (nhỏ) perf trên không sử dụng Guids như là chìa khóa thay vì ints, nhưng không có gì đã ngăn tôi cho đến nay. Đối số quan trọng nhất chống lại Guids là nếu ID được sử dụng bên ngoài ứng dụng, bởi vì chúng thực sự khó đọc to trên điện thoại (như một ví dụ). Sử dụng Guids giải quyết một số vấn đề, nhưng không phải tất cả. Tôi thích Guids, nhưng mở cửa cho các lựa chọn thay thế khác :) –

+0

Nếu Order và OrderRequest được tách ra, nó sẽ là một địa ngục bảo trì, phải không?Ý tôi là, vì họ phản ánh hoàn toàn lẫn nhau, ngoại trừ trường Id, họ sẽ phải cùng nhau phát triển mọi lúc. Hay tôi đang thiếu một cái gì đó? – vorou

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