2015-07-14 17 views
9

Tôi có hai phương pháp khuyến nông nhưLINQ to Entities không hỗ trợ phương pháp mở rộng?

public static IQueryable<T> CurrentVersion(this IQueryable<T> queryable, DateTime date) 
    { 
     return queryable.Where(p => p.CreationDate>date); 
    } 

    public static IEnumerable<T> CurrentVersion(this IEnumerable<T> queryable, DateTime date) 
    { 
     return queryable.Where(p => p.CreationDate>date); 
    } 

Mô hình của tôi đây là

public class Group { 
    .. 
    ICollection<GroupMembers> GroupMembers { get; set; } 
} 

Khi tôi sử dụng từ phương pháp mở rộng trong mọi truy vấn này là ok

var q = Db.Groups.CurrentVersion(); 
var result = q.ToList(); 

Nhưng khi tôi sử dụng nó trong truy vấn diễn ra, tôi gặp lỗi

var q = Db.Groups.SelectMany(p => p.GroupMembers.AsQueryable().CurrentVersion(date)); 

OR 

var q = Db.Groups.SelectMany(p => p.GroupMembers.AsEnumerable().CurrentVersion(date)); 

var result = q.ToList(); // Here I get error 

Lỗi:

LINQ to Entities does not recognize the method 'System.Linq.IQueryable 1[..](System.Linq.IQueryable 1[..., System.DateTime)' method, and this method cannot be translated into a store expression.

Bây giờ tôi có hai câu hỏi:

  1. Tôi googled lỗi này và tìm thấy nhiều vấn đề tương tự như câu hỏi của tôi trong stackoverflow. Tất cả các câu trả lời là "LINQ to Entities không thể chuyển đổi phương thức mở rộng này thành truy vấn SQL". Bây giờ tôi sẽ biết ơn nếu ai đó giúp tôi biết, tại sao truy vấn đầu tiên của tôi không gây ra bất kỳ lỗi nào?

  2. Tôi làm cách nào để thay đổi phương thức tiện ích mở rộng có thể được Linq-to-Entities nhận ra?

Trả lời

6

Truy vấn LINQ cần được dịch sang sql. Khi bạn đã có phần mở rộng CurrentVersion bạn được gọi là inline như thế này:

Db.Groups.CurrentVersion(); 

sau đó EF chỉ gọi phương pháp CurrentVersion, được kết quả đối tượng IQueryable và biến đổi trong để truy vấn. Mặt khác trong trường hợp truy vấn đó:

var q = Db.Groups.SelectMany(p => p.GroupMembers.AsQueryable().CurrentVersion(date)); 

Biểu thức bên trong trong SelectMany có thể không bao giờ được gọi trong mã! Nó có nghĩa là để được dịch sang sql. Vì vậy, nó được coi là đối tượng Expression và sau đó nó được phân tích cú pháp, nhưng trong trường hợp của bạn nó chứa Invoke Expression như bạn đang gọi phương thức nhưng điều này không thể được dịch sang sql từ lý do rõ ràng. Vì vậy, từ bên trong SelectMany lambda parameer bạn không thể gọi bất kỳ phương thức nào, bạn phải cung cấp biểu thức thích hợp. Điều quan trọng nhất được cung cấp bởi phương pháp CurrentVersion là biểu thức lọc. Thay đổi phương pháp của bạn như thế này:

public static Expression<T, bool> CurrentVersion(DateTime date) 
{ 
    return p => p.CreationDate > date; 
} 

Một sử dụng nó như thế này:

var q = Db.Groups.Where(ExpressionsHelper.CurrentVersion(date)); 
... 
Expression<T, bool> filterExpression = ExpressionsHelper.CurrentVersion(date); 
Db.Groups.SelectMany(p => p.GroupMembers.AsQueryable().Where(filterExpression)); 

Nếu bạn whish bạn có thể stil có phương pháp mở rộng chia sẻ lọc logic của bạn với phương pháp mới:

public static IQueryable<T> CurrentVersion(this IQueryable<T> queryable, DateTime date) 
{ 
    return queryable.Where(ExpressionsHelper.CurrentVersion(date)); 
} 
+0

Tôi nghĩ rằng phần mở rộng của bạn không khác với phương pháp mở rộng của tôi bởi vì queryable.Where (ExpressionsHelper.CurrentVersion (ngày)) là equale với queryable.Where (p => p.CreationDate> date); –

+0

Thực sự có thể truy vấn.Where (ExpressionsHelper.CurrentVersion (ngày)) sẽ hoạt động như có thể truy vấn.Where (p => p.CreationDate> date); nhưng đây là mục tiêu, phải không? Tôi đã thay đổi phương thức của bạn để logic lọc của bạn có thể được sử dụng lại, như bạn đã làm. Vì vậy, sự khác biệt nên là phương pháp được đề xuất bởi tôi đang làm việc và EF có thể phân tích nó để truy vấn. – mr100

+0

Nhưng phiên bản của tôi của phương pháp mở rộng CurrentVersion không thể được áp dụng cho truy vấn lồng nhau của bạn! Bạn có thể sử dụng nó chỉ với các truy vấn đơn giản như Db.Groups.Phiên bản hiện tại(); Đối với những phức tạp, bạn cần phải sử dụng Db.Groups.SelectMany (p => p.GroupMembers.AsQueryable(). Where (ExpressionsHelper.CurrentVersion (date))); Phương pháp mở rộng chỉ được trình bày dưới dạng mẫu - nếu bạn muốn có nó, bạn có thể có nó mà không cần sao chép mã. – mr100

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