5

Trong khi xây dựng bởi DAL Repository, tôi tình cờ gặp một khái niệm gọi là Pipes and Filters. Tôi đọc về nó here, ở đây và thấy một màn hình từ here. Tôi vẫn không chắc chắn làm thế nào để đi về việc thực hiện mô hình này. Về mặt lý thuyết, tất cả đều tốt, nhưng làm cách nào chúng ta thực sự thực hiện điều này trong kịch bản doanh nghiệp?Làm cách nào để bạn triển khai mẫu Ống và Bộ lọc với LinqToSQL/Entity Framework/NHibernate?

Tôi sẽ đánh giá cao, nếu bạn có bất kỳ tài nguyên, mẹo hoặc ví dụ ro giải thích cho mẫu này trong ngữ cảnh cho người lập bản đồ dữ liệu/ORM được đề cập trong câu hỏi.

Cảm ơn trước !!

+0

Vui lòng thêm nhận xét nếu bạn quyết định từ chối câu hỏi vì bất kỳ lý do gì. – Perpetualcoder

+0

Đã xảy ra sự cố với câu hỏi? – Perpetualcoder

Trả lời

11

Cuối cùng, LINQ trên IEnumerable<T> việc triển khai đường ống và bộ lọc. IEnumerable<T> là một API phát trực tuyến - có nghĩa là dữ liệu sẽ được trả về khi bạn yêu cầu (thông qua các khối lặp), thay vì tải mọi thứ cùng một lúc và trả về một bộ đệm lớn.

này có nghĩa là truy vấn của bạn:

var qry = from row in source // IEnumerable<T> 
      where row.Foo == "abc" 
      select new {row.ID, row.Name}; 

là:

var qry = source.Where(row => row.Foo == "abc") 
      .Select(row = > new {row.ID, row.Name}); 

như bạn liệt kê trên đây, nó sẽ tiêu thụ dữ liệu một cách lười biếng. Bạn có thể thấy đồ họa này với số Visual LINQ của Jon Skeet. Những thứ duy nhất phá vỡ đường ống là những thứ buộc phải đệm; OrderBy, GroupBy, v.v. Đối với khối lượng lớn, Jon và bản thân tôi đã làm việc theo số Push LINQ để thực hiện tổng hợp mà không bị giật trong các trường hợp như vậy.

IQueryable<T> (hiển thị bởi hầu hết các công cụ ORM - LINQ-to-SQL, Khuôn khổ thực thể, LINQ-to-NHibernate) là một con thú hơi khác; bởi vì công cụ cơ sở dữ liệu sẽ thực hiện hầu hết các công việc nặng nhọc, cơ hội là hầu hết các bước đã được thực hiện - tất cả những gì còn lại là tiêu thụ một IDataReader và dự án này cho các đối tượng/giá trị - nhưng đó vẫn là một đường ống (IQueryable<T> thực hiện IEnumerable<T>) trừ khi bạn gọi .ToArray(), .ToList(), vv

liên quan để sử dụng trong doanh nghiệp với ... my view là nó là tốt để sử dụng IQueryable<T> viết các truy vấn composable bên trong kho, nhưng họ không nên nghỉ kho lưu trữ - vì điều đó sẽ làm cho hoạt động nội bộ của đối tượng lưu trữ đến người gọi, vì vậy bạn sẽ không thể kiểm tra đơn vị/hồ sơ/tối ưu hóa/v.v. mọi thứ trong kho lưu trữ, nhưng trả lại danh sách/mảng. Điều này cũng có nghĩa là kho lưu trữ của tôi vẫn không biết về việc triển khai.

Đây là một sự xấu hổ - vì sự cám dỗ để "trả lại" IQueryable<T> từ phương thức lưu trữ là khá lớn; ví dụ, điều này sẽ cho phép người gọi thêm phân trang/bộ lọc/etc - nhưng hãy nhớ rằng họ chưa thực sự tiêu thụ dữ liệu. Điều này làm cho việc quản lý tài nguyên trở nên đau đớn. Ngoài ra, trong MVC, bạn cần phải đảm bảo rằng các điều khiển gọi .ToList() hoặc tương tự, để không phải là chế độ xem đang kiểm soát truy cập dữ liệu (nếu không, bạn không thể kiểm tra bộ điều khiển một cách chính xác).

Một (IMO) sử dụng an toàn các bộ lọc trong Dal sẽ là những thứ như:

public Customer[] List(string name, string countryCode) { 
    using(var ctx = new CustomerDataContext()) { 
     IQueryable<Customer> qry = ctx.Customers.Where(x=>x.IsOpen); 
     if(!string.IsNullOrEmpty(name)) { 
      qry = qry.Where(cust => cust.Name.Contains(name)); 
     } 
     if(!string.IsNullOrEmpty(countryCode)) { 
      qry = qry.Where(cust => cust.CountryCode == countryCode); 
     } 
     return qry.ToArray(); 
    } 
} 

lọc Dưới đây chúng tôi đã thêm on-the-fly, nhưng không có gì xảy ra cho đến khi chúng ta gọi là ToArray. Tại thời điểm này, dữ liệu thu được và trả về (xử lý bối cảnh dữ liệu trong tiến trình). Điều này có thể được kiểm tra đầy đủ. Nếu chúng tôi đã làm một cái gì đó tương tự nhưng vừa trở về IQueryable<T>, người gọi có thể làm điều gì đó như:

var custs = customerRepository.GetCustomers() 
     .Where(x=>SomeUnmappedFunction(x)); 

Và tất cả của một đột ngột Dal của chúng tôi bắt đầu thất bại (không thể dịch SomeUnmappedFunction để TSQL, vv). Tuy nhiên, bạn vẫn có thể thực hiện những điều thú vị trong kho lưu trữ.

Điểm đau duy nhất ở đây là nó có thể đẩy bạn có một vài tình trạng quá tải để hỗ trợ các kiểu gọi khác nhau (có/không có phân trang, v.v ...). Cho đến khi optional/named parameters đến, tôi tìm thấy câu trả lời tốt nhất ở đây là sử dụng các phương thức mở rộng trên giao diện; theo cách đó, tôi chỉ cần một thi kho bê tông:

class CustomerRepository { 
    public Customer[] List(
     string name, string countryCode, 
     int? pageSize, int? pageNumber) {...} 
} 
interface ICustomerRepository { 
    Customer[] List(
     string name, string countryCode, 
     int? pageSize, int? pageNumber); 
} 
static class CustomerRepositoryExtensions { 
    public static Customer[] List(
      this ICustomerRepository repo, 
      string name, string countryCode) { 
     return repo.List(name, countryCode, null, null); 
    } 
} 

Bây giờ chúng ta có quá tải ảo (như phương pháp khuyến nông) trên ICustomerRepository - vì vậy người gọi chúng tôi có thể sử dụng repo.List("abc","def") mà không cần phải xác định phân trang.


Cuối cùng - không có LINQ, việc sử dụng ống và bộ lọc trở nên đau đớn hơn nhiều. Bạn sẽ viết một số loại truy vấn dựa trên văn bản (TSQL, ESQL, HQL). Bạn rõ ràng có thể nối thêm chuỗi, nhưng nó không phải là rất "ống/bộ lọc" -ish. "API tiêu chí" tốt hơn một chút - nhưng không thanh lịch như LINQ.