2012-10-15 28 views
5

Tôi cố gắng để hiểu một số hàm ý thực hiện LINQ từ ebook miễn phí này bằng cách RedGate ftp://support.red-gate.com/ebooks/under-the-hood-of-net-memory-management-part1.pdfCó thể gọi phương thức có tên trong cuộc gọi đến đâu không?

Trên trang 157-158 trong cuốn sách này, họ đã tạo ra theo gương.

Order[] pastDueAccounts = null; 
DateTimedueDate = DateTime.Today.AddDays(-7); 
using(varcontext = new Context())  
{ 
    pastDueAccounts = context.Accounts.Where(account => account.DueDate < dueDate).ToArray(); 
} 

Sau đó, họ tính lại một phần biểu thức lamda thành hàm sau.

public bool PastDueAccount(Account account) 
{ 
    return account.DueDate < DateTime.Today.AddDays(-7); 
} 

Cuối cùng, họ đã sử dụng chức năng này như sau.

Order[] pastDueAccounts = null; 
using(varcontext = new Context()) 
{ 
    pastDueAccounts = context.Accounts.Where(account => PastDueAccount(account)).ToArray(); 
} 

Dựa trên những gì tôi đã nghiên cứu cho đến nay, không thể nhận truy vấn LINQ này là LINQ sẽ không thể dịch thành biểu thức cửa hàng. Tôi tự hỏi nếu ví dụ này là sai và chỉ đơn giản là không thể chạy hoặc nếu tôi chỉ có thời gian khó khăn nhận được nghe nói của tôi xung quanh về cách mô phỏng vấn đề này?

Trả lời

3

Như casperOne đã nói, bạn không thể thực hiện điều đó bằng chức năng. Câu trả lời này là một cách để làm những gì bạn cần làm (sử dụng lại bộ lọc ở đâu).

Bạn có thể tạo Expression ở nơi nào đó bạn có thể truy cập, sau đó sử dụng lại.

System.Linq.Expressions.Expression<Func<Account, bool>> pastDueAccountFunc = account => account.DueDate < System.Data.Objects.EntityFunctions.AddDays(DateTime.Now, -7);

Sau đó, để sử dụng nó sau này:

var pastDueAccounts = context.Accounts.Where(pastDueAccountFunc);

này là đầy đủ mã Tôi đang sử dụng với điều này:

System.Linq.Expressions.Expression<Func<SomeNeatEntity, bool>> func = x => x.DateCreated < System.Data.Objects.EntityFunctions.AddDays(DateTime.Now, -7); 

var entities = new MyEntities(); 

var t = entities.SomeNeatEntities.Where(func); 
Console.WriteLine(t.Count()); 

var h = entities.SomeNeatEntities.Where(x => x.SomeField != null).Where(func); 
Console.WriteLine(h.Count()); 

MyEntitiesObjectContext trong dự án .
entities.SomeNeatEntitiesObjectSet<SomeNeatEntity>.

+0

Điều này là sai và sẽ không hoạt động vì đây không phải là biểu thức lambda và không thể được nhà cung cấp truy vấn đánh giá. – casperOne

+0

Tôi thực sự đã làm việc này chống lại thiết lập EF mà tôi có. – Gromer

+3

Nếu nó đang hoạt động, bạn đang lọc * trên máy khách * và cuộc gọi đến 'Where' đang đánh giá kết quả từ' IEnumerable 'và * không * dịch bộ lọc sang phía máy chủ. Hãy nhớ rằng, 'IQueryable ' có nguồn gốc từ 'IEnumerable ', vì vậy tất cả các phương thức mở rộng trên' IEnumerable 'sẽ hoạt động trên' IQueryable 'và nó không phải lúc nào cũng rõ ràng. – casperOne

8

Bạn chính xác, điều này sẽ không thể được gọi bởi LINQ-to-Entities theo cách nó được hiển thị.

Cách duy nhất nó có thể được sử dụng trong LINQ-to-Đối tượng là:

  • Tạo tương đương với chức năng ở phía máy chủ.
  • Map the function in the model thích hợp để dịch cuộc gọi chính xác.
+0

Sử dụng 'AsExpandable()' của LINQKit là một lựa chọn khác để bạn có thể sử dụng các phương thức biểu thức có thể được dịch sang SQL. – Ocelot20

+0

@casperOne: Về nhận xét của bạn về di chuột qua Nơi trong VS.NET trên Nơi được gọi cho t và h, làm cách nào để xác định thời điểm gọi ở đâu với IEnumerable và khi nào nên gọi ở đâu với IQueryable? –

+0

@palmsnow Về cơ bản, suy luận kiểu xác định mức độ phù hợp nhất. Trong trường hợp cụ thể này, vì tham số là một 'Func ' và không phải là một 'Biểu thức >' nó không thể khớp với 'Queryable.Where' (có một biểu thức), chỉ' Enumerable.Where' (mà có một đại biểu). – casperOne

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