2012-09-13 26 views
6

Tôi đang sử dụng bây giờ khuôn khổ thực thể- nhưng đó là một vấn đề "chia sẻ" giữa tất cả ORM và thậm chí IEnumerable.Làm thế nào để lọc IEnumerable dựa trên một tham số đầu vào thực thể

Hãy nói rằng tôi có một phương pháp trong MVC trông như thế này:

[HttpPost] 
public ActionResult Foo(FooModel model) 
{ 
    var context = new Context(); -- The EF session 
    var data = context.Foo.Where(???).ToList(); 
    return View(data); 
} 

tôi muốn truy vấn bối cảnh dựa trên các thông số đầu vào như:

var data = context.Foo.Where(x => x.Date == model.Date && 
          x.Name == model.Name && 
          x.ItemCode = model.ItemCode).ToList(); 

Nhưng nó phức tạp hơn thế nữa, bởi vì nếu một trong các tham số ở trên (Date \ Name \ ItemCode) là không, tôi không muốn đưa nó vào trong truy vấn.
Nếu mã cứng tôi nó có thể trông tương tự như sau:

var query = context.Foo; 

if (model.Date != null) 
    query =query.Where(x => x.Date == model.Date); 

if (model.ItemCode != null) 
    query =query.Where(x => x.ItemCode == model.ItemCode); 
... 

Phải có một cách đơn giản hơn thế này.
Tôi cần một cách để tạo biểu thức loại Expression<T, bool> để sử dụng trong phương thức Vị trí.

[HttpPost] 
public ActionResult Foo(FooModel model) 
{ 
    var context = new Context(); -- The EF session 
    var data = context.Foo.Where(THE_EXPRESSION).ToList(); 
    return View(data); 
} 

Có cách tích hợp để xây dựng biểu thức đó không? Có một gói trong nuget mà nó?


Cập nhật: Có thể có hơn 30 properites trong mô hình thực thể; viết 30 lần Địa điểm cho mỗi truy vấn có thể là một cơn đau ở cổ:

.Where(model.Date != null, x => x.Date == model.Date) 
.Where(model.Name != null, x => x.Name == model.Name) 
.Where(model.ItemCode != null, x => x.ItemCode == model.ItemCode) 
... 
... 
... 
.ToList(); 

Trả lời

5

Hãy thử điều đó. Điều này đang sử dụng phản ánh và biểu thức để tạo truy vấn động. Tôi đã thử nghiệm nó chỉ với các đối tượng.

static IQueryable<T> Filter<T>(IQueryable<T> col, T filter) 
{ 
    foreach (var pi in typeof(T).GetProperties()) 
    { 
     if (pi.GetValue(filter) != null) 
     { 
      var param = Expression.Parameter(typeof(T), "t"); 
      var body = Expression.Equal(
       Expression.PropertyOrField(param, pi.Name), 
       Expression.PropertyOrField(Expression.Constant(filter), pi.Name)); 
      var lambda = Expression.Lambda<Func<T, bool>>(body, param); 
      col = col.Where(lambda); 
     } 
    } 

    return col; 
} 
+0

Một ví dụ cho thấy cách sử dụng phương pháp này sẽ rất hữu ích. – devinbost

5

Phương pháp mã hóa cứng của bạn là phương pháp tốt nhất nói chung.

Tuy nhiên, bạn có thể cố gắng làm cho cuộc sống của mình dễ dàng hơn một chút bằng cách viết một phương pháp mở rộng thích hợp để giúp giữ mã sạch.

Hãy thử điều này ví dụ:

public static class QueryableEx 
{ 
    public static IQueryable<T> Where<T>(
     this IQueryable<T> @this, 
     bool condition, 
     Expression<Func<T, bool>> @where) 
    { 
     return condition ? @this.Where(@where) : @this; 
    } 
} 

Bây giờ bạn có thể viết mã này:

[HttpPost] 
public ActionResult Foo(FooModel model) 
{ 
    using (var context = new Context()) 
    { 
     var data = context.Foo 
      .Where(model.Date != null, x => x.Date == model.Date) 
      .Where(model.Name != null, x => x.Name == model.Name) 
      .Where(model.ItemCode != null, x => x.ItemCode == model.ItemCode) 
      .ToList(); 
     return View(data); 
    } 
} 

(Xin đừng quên để xử lý ngữ cảnh của bạn hoặc sử dụng using để làm điều đó cho bạn.)

+0

+1 Điều này cho phép phiếu bầu của tôi cho phép người dùng tìm kiếm một bảng lớn bằng N! hoán vị khác nhau làm cho nó một cơn ác mộng để chỉ số ở cấp db. Bằng cách làm cho mỗi bộ lọc hiển thị cho dev, thre ít nhất là một số hiển thị trong truy vấn kết quả và có thể khiến một số suy nghĩ lại về trường nào (hoặc các kết hợp của chúng) có thể được hiển thị cho người dùng. – StuartLC

+0

Cảm ơn bạn đã nhập và ý tưởng của mình.Nhưng nếu mô hình thực thể của tôi có hơn ** 30 ** thích hợp nó viết 30 lần ở đâu (...) có thể là một nỗi đau. – gdoron

+0

@gdoron - Có, nhưng bạn phải viết chúng ở đâu đó. Nếu bạn cố gắng làm điều này với sự phản ánh và xây dựng các biểu thức sau đó tôi sợ bạn bây giờ có hai vấn đề. – Enigmativity

1

Tôi nghĩ bạn nên đóng gói logic của bạn vào thực thể Foo của bạn, ví dụ:

public Foo 
    { 
    public bool isMatch(Model model) 
    { 
     // check your rules and return result 
    } 
    } 

và sử dụng trong LINQ. Hoặc xem Specification pattern

+1

Điều đó chỉ hoạt động với LINQ to Objects chứ không phải với Entity Framework. –

+0

Bạn có thể trả về Biểu thức công khai > IsSatisfiedBy() – syned

+0

Hoàn toàn làm sai lệch thực thể của bạn. –

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