2010-09-28 16 views
6

Tôi đang trải qua một cuộc khủng hoảng kiến ​​trúc triết học giữa sự nghiệp. Tôi thấy những dòng rất rõ ràng giữa những gì được coi là mã khách hàng (UI, Web Services, MVC, MVP, vv) và Service Layer. Tuy nhiên, các đường từ lớp Dịch vụ trở nên mờ hơn theo từng phút. Và tất cả bắt đầu với khả năng truy vấn mã với LINQ và khái niệm tải Lười biếng.Khả năng truy vấn và tải kém trong C# có làm mờ các dòng truy cập dữ liệu và Logic kinh doanh không?

Tôi đã tạo Lớp kinh doanh bao gồm Hợp đồng và triển khai. Các triển khai sau đó có thể có sự phụ thuộc vào các Hợp đồng khác và như vậy. Điều này được xử lý thông qua một IoC Container với DI. Có một dịch vụ xử lý DataAccess và tất cả những gì nó làm là trả về một UnitOfWork. UnitOfWork này tạo ra một giao dịch khi mở rộng và cam kết dữ liệu trên phương thức Commit. [View this Article (Testability and Entity Framework 4.0)]:

public interface IUnitOfWork : IDisposable { 
    IRepository<T> GetRepository<T>() where T : class; 
    void Commit(); 
} 

Các Repository là chung chung và các công trình chống lại hai triển khai (EF4 và một InMemory DataStore). T được tạo thành từ các POCO được tạo ra từ lược đồ cơ sở dữ liệu hoặc ánh xạ EF4. Testability được xây dựng trong thiết kế Repository. Chúng tôi có thể tận dụng việc triển khai trong bộ nhớ để khẳng định kết quả với kỳ vọng.

public interface IRepository<T> where T : class { 
    IQueryable<T> Table { get; } 
    void Add(T entity); 
    void Remove(T entity); 
} 

Khi nguồn dữ liệu bị trừu tượng, IQueryable vẫn cung cấp cho tôi khả năng tạo truy vấn ở bất kỳ nơi nào tôi muốn trong logic nghiệp vụ. Đây là một ví dụ.

public interface IFoo { 
    Bar[] GetAll(); 
} 

public class FooImpl : IFoo { 
    IDataAccess _dataAccess; 
    public FooImpl(IDataAccess dataAccess) { 
     _dataAccess = dataAccess; 
    } 

    public Bar[] GetAll() { 
     Bar[] output; 
     using (var work = _dataAccess.DoWork()) { 
      output = work.GetRepository<Bar>().Table.ToArray(); 
     } 
     return output; 
    } 
} 

Giờ đây, bạn có thể xem các truy vấn có thể phức tạp hơn như thế nào khi bạn thực hiện kết hợp với bộ lọc phức tạp.

Vì vậy, câu hỏi của tôi là:

  1. Liệu nó có vấn đề là không có sự khác biệt rõ ràng giữa BLL và DAL?.
  2. Khả năng truy vấn được coi là truy cập dữ liệu hoặc logic nghiệp vụ khi ở phía sau lớp Kho lưu trữ hoạt động như trừu tượng InMemory?

Bổ sung: Tôi càng nghĩ về điều đó, có lẽ câu hỏi thứ hai là câu hỏi duy nhất nên được hỏi.

Trả lời

6

Tôi nghĩ cách tốt nhất để trả lời các câu hỏi của bạn là lùi lại một chút và xem xét lý do tách biệt giữa các lớp logic kinh doanh và các lớp truy cập dữ liệu là thực hành được khuyến nghị.Trong tâm trí của tôi, lý do rất đơn giản: giữ logic nghiệp vụ tách biệt với lớp dữ liệu vì logic nghiệp vụ là nơi giá trị, lớp dữ liệu và logic nghiệp vụ sẽ cần phải thay đổi theo thời gian nhiều hơn hoặc ít độc lập hơn với từng giá trị. khác, và logic nghiệp vụ cần phải đọc được mà không cần phải có kiến ​​thức chi tiết về tất cả các lớp truy cập dữ liệu làm gì.

Vì vậy, các phép thử cho thể dục dụng cụ truy vấn của bạn nắm này:

  1. Bạn có thể thực hiện thay đổi lược đồ dữ liệu trong hệ thống của bạn mà không làm xáo trộn một phần đáng kể của logic kinh doanh?
  2. Logic kinh doanh của bạn có thể đọc được cho bạn và với các nhà phát triển C# khác không?
+1

+1 cho điểm đầu tiên, đặc biệt là – arootbeer

+2

+1. Mục đích đầu tiên, triết học thứ hai. –

+0

Điểm đầu tiên của bạn là lo lắng của tôi. Mặc dù vậy, EF4 có thể tạo các đối tượng miền sudo với các khả năng ánh xạ của nó, nếu bạn thực hiện thay đổi trong lược đồ DB, rất có thể bạn muốn truyền những thay đổi đó cho các đối tượng EF4 - do đó ảnh hưởng đến logic nghiệp vụ của bạn. Tác động đó có thể được giảm thiểu bằng cách thực hiện hồi quy trên các bài kiểm tra đơn vị của bạn. Nhưng thay đổi là một sự thay đổi. –

1

1. Chỉ khi bạn quan tâm nhiều hơn đến triết lý hơn là hoàn thành công việc. :)

2. Tôi muốn nói đó là logic kinh doanh vì bạn có sự trừu tượng ở giữa. Tôi sẽ gọi đó là một phần kho lưu trữ của DAL, và bất cứ thứ gì sử dụng nó, BL.

Nhưng vâng, điều này cũng bị mờ đối với tôi. Tôi không nghĩ rằng nó quan trọng mặc dù. Điểm của việc sử dụng các mẫu như thế này là viết một mã sạch, có thể sử dụng dễ dàng để giao tiếp cùng một lúc, và mục tiêu đó được thực hiện theo một trong hai cách.

1

1.Đó là vấn đề không có sự phân biệt rõ ràng giữa BLL và DAL ?.

Nó chắc chắn quan trọng! Bất kỳ lập trình viên nào sử dụng thuộc tính Bảng của bạn cần phải hiểu các nhánh (vòng tròn cơ sở dữ liệu, dịch truy vấn, theo dõi đối tượng). Điều đó xảy ra với các lập trình viên cũng đọc các lớp logic kinh doanh.

2.Là truy vấn được coi là truy cập dữ liệu hoặc logic nghiệp vụ khi ở phía sau lớp Kho lưu trữ hoạt động như trừu tượng InMemory?

Trừu tượng là một tấm chăn mà chúng tôi ẩn các vấn đề của chúng tôi theo.

Nếu trừu tượng của bạn là hoàn hảo, thì các truy vấn có thể được coi là hoạt động dựa trên bộ sưu tập trong bộ nhớ và do đó chúng không phải là truy cập dữ liệu.

Tuy nhiên, sự trừu tượng bị rò rỉ. Nếu bạn muốn các truy vấn có ý nghĩa trong thế giới dữ liệu, phải có nỗ lực để làm việc ở trên và vượt quá sự trừu tượng hóa. Đó là nỗ lực thêm (mà đánh bại trừu tượng) tạo ra mã truy cập dữ liệu.


Một số ví dụ:

output = work.GetRepository<Bar>().Table.ToArray(); 

Đây là mã là (trừu tượng) tốt. Nhưng trong thế giới dữ liệu nó kết quả trong việc quét toàn bộ một bảng và (ít nhất là nói chung) câm!


badquery = work.GetRepository<Customer>().Table.Where(c => c.Name.Contains("Bob")).ToArray(); 
goodquery = work.GetRepository<Customer>().Table.Where(c => c.Name.StartsWith("Bob")).ToArray(); 

Goodquery là tốt hơn so với truy vấn xấu khi có một chỉ mục trên Customer.Name. Nhưng thực tế đó không có sẵn cho chúng tôi trừ khi chúng tôi nâng mức trừu tượng.


badquery = work.GetRepository<Customer>().Table 
    .GroupBy(c => c.Orders.Count()) 
    .Select(g => new 
    { 
    TheCount = g.Key, 
    TheCustomers = g.ToList() 
    }).ToArray(); 
goodquery = work.GetRepository<Customer>().Table 
    .Select(c => new {Customer = c, theCount = c.Orders.Count()) 
    .ToArray() 
    .GroupBy(x => x.theCount) 
    .Select(g => new 
    { 
    TheCount = g.Key, 
    TheCustomers = g.Select(x => x.Customer).ToList() 
    }) 
    .ToArray(); 

goodquery là tốt hơn so với truy vấn xấu từ badquery sẽ requery cơ sở dữ liệu bằng phím nhóm, cho từng nhóm (và tồi tệ hơn, nó là rất khó có một chỉ số để giúp khách hàng lọc bởi c.Orders.Count()).


Kiểm tra được tích hợp vào thiết kế Kho lưu trữ.Chúng tôi có thể tận dụng việc triển khai InMemory để khẳng định kết quả với kỳ vọng.

Không được ảo tưởng rằng các truy vấn của bạn đang được thử nghiệm nếu bạn thực sự chạy chúng với bộ sưu tập trong bộ nhớ. Các truy vấn đó là không thể thực hiện được trừ khi một cơ sở dữ liệu có liên quan.

+0

Sau khi suy nghĩ về nó, tôi hiểu điểm của bạn về Trừu tượng rò rỉ. Mặc dù nguồn của IQueryable đang được trừu tượng hóa, bất kỳ truy vấn nào được tạo ra trên lớp logic nghiệp vụ đều tạo ra các kịch bản lệnh được thực hiện bởi EF4 một cách hiệu quả. Vì vậy, rò rỉ. Vì vậy, đây là câu hỏi tiếp theo của tôi, nên IQueryable với tải lười biếng bao giờ được tiếp xúc bên ngoài DAL? Phrased một cách khác nhau, các EF4 ObjectSet có một kết nối mở cho DB bao giờ được trừu tượng vượt ra ngoài DAL? –

+0

Bao giờ? Nếu bạn đang hoạt động trong các điều khoản đen trắng như vậy, thì không. Các lập trình viên đang viết logic nghiệp vụ và không có hiểu biết về cơ sở dữ liệu sẽ không có quyền truy cập vào trình tạo truy vấn. –

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