2014-10-27 19 views
5

Tôi hiện đang làm việc với một codebase sử dụng Mô hình miền không ổn định và tôi đang cố gắng chuyển nhiều logic hơn vào các mô hình miền trong quá trình chuyển sang Mô hình miền và Miền Thiết kế điều khiển, nhưng tôi đang đấu tranh với vấn đề sau.Cách đặt trường riêng tư trên mô hình miền trong kho lưu trữ

Tôi có một mô hình miền gọi là Job mà trông như thế này,

public class Job 
{ 
    private DateTime _someOtherDate; 
    private DateTime _lastUpdated; 

    // this may be called from many different services 
    public void SetLastUpdated() 
    { 
    _lastUpdated = DateTime.UtcNow; 
    } 
} 

Tại một số điểm trong thời gian, trong quá trình xử lý một công việc tôi muốn thiết lập ngày cập nhật cuối cùng của công việc với thời điểm cụ thể. Để làm điều này tôi đã tạo ra một setter công cộng cho nó như bạn có thể thấy ở trên.

Sự cố phát sinh khi tôi rút lại công việc từ cơ sở dữ liệu trong kho lưu trữ của mình, vì hiện tại tôi không có công cụ đặt chỗ cho trường này vì tôi đã hạn chế việc đó SetLastUpdated().

Ai đó có thể xin tư vấn về làm thế nào tôi có thể cho phép khách sạn này được thiết lập trong việc thực hiện kho khi lấy công việc, nhưng không phải từ các dịch vụ mà nó được giới hạn gọi SetLastUpdated().

Cập nhật 1) Tôi đã cập nhật câu hỏi là sử dụng ngày bắt đầu là ví dụ không tốt.

Cập nhật 2) Từ câu trả lời được đưa ra, cách duy nhất tôi có thể thấy điều này được thực hiện là không sử dụng AutoMapper trong kho, thêm một hàm tạo vào lớp Job để thiết lập _lastUpdated và sử dụng nó khi xây dựng công việc được trả về trong phương thức truy xuất công việc của kho lưu trữ.

+0

Bạn đang sử dụng loại mẫu nào để làm ẩm mô hình miền của mình? Bạn đang sử dụng ORM, hay vật lưu niệm? Nhà thầu của bạn trông như thế nào? – arootbeer

+0

Tôi đang sử dụng AutoMapper để ánh xạ các mô hình Khung thực thể trở lại các mô hình miền. Đây là nơi ngày bắt đầu sẽ được đặt. Không có các nhà xây dựng trên các mô hình miền, chúng thiếu máu do thiết kế. – Jonathan

+0

Không giống như các trang web diễn đàn, chúng tôi không sử dụng "Cảm ơn" hoặc "Bất kỳ trợ giúp được đánh giá cao" hoặc chữ ký nào trên [như vậy]. Xem "[Nên 'Xin chào', 'cảm ơn', dòng giới thiệu và lời chào được xóa khỏi bài đăng không?] (Http://meta.stackexchange.com/questions/2950/should-hi-thanks-taglines-and-salutations-be –

Trả lời

1

Một cách tiếp cận phổ biến là sử dụng nhà thầu cho điều này

public class Job 
{ 
    private DateTime _startDate; 

    public void Job() 
    { 
    _startDate = DateTime.UtcNow; 
    } 

    public void Job(DateTime dt) 
    { 
    // check DateTime kind, this could be source of a bug 
    if(dt.Kind != DateTimeKind.Utc) throw new ... 
    _startDate = dt; 
    } 
} 

Bạn cần phải vạch trần này phương pháp/bất động sản một cách này hay cách khác. Nếu kho lưu trữ có thể thiết lập nó, bạn có thể thiết lập nó từ các vị trí khác. Nếu bạn cố gắng để thông minh về điều này (bạn có thể, ví dụ bằng cách sử dụng giao diện), bạn sẽ có được một nguy cơ overengineering.

+0

Xin chào oleksii, Kiểm tra thú vị bằng cách sử dụng. Xin cảm ơn! Tôi nghĩ rằng sử dụng ngày bắt đầu trong ví dụ này là một ý tưởng tồi Kiểm tra cập nhật của tôi – Jonathan

+0

@ Jonathan C# DateTime là nỗi đau trong một mông để làm việc với Bạn sẽ thấy ngoại lệ này sẽ được bắn rất nhiều.Chúng tôi đã có một vài lỗi với điều này.Khi ORM (ORM) Automapper) tạo ra một DateTime mới, theo mặc định các loại là không xác định, nếu tôi nhớ chính xác.Đối tượng này sẽ vui vẻ chấp nhận ngày utc, nhưng sẽ "quên" để thiết lập các loại utc – oleksii

1

Một trong những lý do chính khiến bạn làm DDD là tận dụng lợi thế của khả năng đột biến được quản lý có thể được cung cấp bằng cách đóng gói. Đó là luôn luôn sẽ bắt đầu với hàm tạo.

Nói chung, đây là loại công việc một ORM được thiết kế đặc biệt để thực hiện, tuy nhiên nó cũng có thể tận dụng lợi thế của bất kỳ DTOs hiện mà có thể đã được ánh xạ vào các đối tượng miền bằng memento pattern:

public Job() { 
    _lastUpdated = DateTime.UtcNow; 
    // ... 
} 

public Job(JobData data) { 
    _lastUpdated = data.LastUpdated; 
    //... 
} 

re: AutoMapper - đã một thời gian kể từ khi tôi sử dụng, nhưng phải là possible for you to instruct it to access fields using reflection in the configuration.

+0

Trong khi bạn có điểm tốt, tôi không hiểu một vài điều đầu tiên, mã OP không có getter hoặc setter cho thời gian ngày cánh đồng. Chỉ có một phương pháp để "đặt nó thành utc bây giờ". Vì vậy, mã bên ngoài không thể nhìn thấy nó hoặc thiết lập nó. Do đó "mã hiện tại không thực sự ngăn cản _startDate bị thay đổi tại bất kỳ thời điểm nào trong tương lai" dường như là sai. Thứ hai, mô hình lưu niệm là tốt cho việc khôi phục trạng thái của một đối tượng đến các trạng thái trước đó. Tôi không thể thấy nó có liên quan như thế nào trong ngữ cảnh này. – oleksii

+0

@oleksii Chữ ký phương thức mà tôi đã tham chiếu là 'public void SetStartDate()', mà từ đó OP đã chỉnh sửa thành 'public void SetLastUpdated()', mà câu lệnh của tôi ít được áp dụng hơn. Tôi sẽ chỉnh sửa phần đó. Đối với mô hình 'memento' là tốt cho việc khôi phục trạng thái của một đối tượng về trạng thái trước đó của nó - bạn nghĩ gì về dữ liệu trong cơ sở dữ liệu nếu không phải * trạng thái trước đó * của đối tượng? – arootbeer

+0

Nó có thể được coi là trạng thái trước đó, nếu tất cả các công việc, trên thực tế, cùng một đối tượng - chỉ đơn thuần là ghi lại các trạng thái khác nhau của cùng một đối tượng. Nhưng một bảng thường sẽ lưu trữ nhiều công việc, có nhiều khả năng không phải là cùng một công việc.Memento lưu trữ các đột biến của cùng một đối tượng, nhưng nó khó có thể được áp dụng để lưu trữ các đột biến của các đối tượng khác nhau theo cách này. Có lý? – oleksii

2

Như tôi thấy, bạn có nhiều tùy chọn khác nhau.

Lựa chọn 1

Giả sử rằng kho của bạn có hai phương pháp:

public IEnumerable<Job> ReadAll() { ... } 
public int CreateJob(Job job) { ... } 

Bạn có thể cung cấp cho các lớp Job hai nhà thầu, một trong đó có một DateTime và điều đó không.

public class Job 
{ 
    public Job(DateTime startDate) 
    { 
     this.StartDate = startDate; 
    } 

    public Job() : this(DateTime.UtcNow) 
    { 

    } 

    public DateTime StartDate { get; private set; } 
} 

này không ngăn cản các dịch vụ từ gọi là "sai" constructor, nhưng ít nhất nó giao tiếp tùy chọn gọi nó mà không có sự startDate đến người gọi.

Lựa chọn 2

Làm việc với hai Job lớp khác nhau.

kho của bạn có thể trông giống như thay vì điều này:

public IEnumerable<Job> ReadAll() { ... } 
public int CreateJob(NewJob newJob) { ... } 

Và lớp NewJob có thể trông giống như:

public class NewJob 
{ 
    public NewJob() 
    { 
     this.StartDate = DateTime.UtcNow; 
    } 

    public DateTime StartDate { get; private set; } 
} 

này truyền đạt ý định tốt hơn, bởi vì phương pháp của kho Create chỉ chấp nhận một thể hiện của NewJob do đó, người dùng của mô hình sẽ bị buộc phải tạo một NewJob thay vì Job.

Lựa chọn 3

Bỏ qua StartDate trong phương pháp của repostory Create và luôn đặt nó vào DateTime.UtcNow trong phương pháp này. Hoặc thậm chí đi xa như vậy để tạo ra một kích hoạt Insert trong cơ sở dữ liệu đặt nó.

+0

Cảm ơn bạn đã trả lời Klaus. Tôi nghĩ việc sử dụng ngày bắt đầu trong ví dụ là một ý tưởng tồi. Kiểm tra cập nhật của tôi. – Jonathan

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