2015-07-14 3 views
9

У меня есть два метода расширения, как этотLINQ to Entities не поддерживает метод расширения?

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); 
    } 

Моя модель

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

Когда я использую от метода расширения в этом запросе все нормально

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

Но когда я использую его in flowing query Я получаю ошибку

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 

Ошибки:

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.

Теперь у меня есть два вопроса:

  1. Я гугл этой ошибки и нашел много проблем, так же, как мой вопрос в StackOverflow. Все ответы были: «Linq to Entities не может преобразовать этот метод расширения в SQL-запрос». Теперь я был бы признателен, если кто-нибудь поможет мне узнать, почему мой первый запрос не вызывает никаких ошибок?

  2. Как изменить метод расширения, который может быть распознан Linq-to-Entities?

ответ

6

Запрос Linq необходимо перевести на sql. Когда у вас есть расширение CurrentVersion под названием рядный, как это:

Db.Groups.CurrentVersion(); 

затем EF просто вызывает метод CurrentVersion, получает в результате IQueryable объект и преобразуется для запроса. С другой стороны, в случае этого запроса:

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

Внутреннее выражение в SelectMany не может быть никогда не вызывается в коде! Он предназначен для перевода на sql. Таким образом, он рассматривается как объект Expression и затем анализируется, но в вашем случае он содержит Invoke Expression, поскольку вы вызываете метод, но это невозможно перевести на sql по очевидной причине. Таким образом, из параметра Selectmany lambda parameer вы не можете вызывать какой-либо метод, вы должны предоставить правильное выражение. Наиболее ценной вещью, предоставляемой методом CurrentVersion, является фильтрация выражения. Измените метод так:

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

использовать его как это:

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

Если вы свистеть вы можете стил иметь свой метод расширения фильтрации разделение логики с новым методом:

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

Я думаю, что ваше расширение не отличается от моего метода расширения, потому что queryable.Where (ExpressionsHelper.CurrentVersion (date)) является equale с запросом. Где (p => p.CreationDate> date); –

+0

Действительно queryable.Where (ExpressionsHelper.CurrentVersion (date)) должен работать как queryable.Where (p => p.CreationDate> date); но это была цель, не так ли? Я изменил свой метод, чтобы ваша логика фильтрации могла быть повторно использована, как вы это делали. Поэтому разница должна заключаться в том, что метод, предложенный мной, работает, и EF может разобрать его на запрос. – mr100

+0

Но моя версия метода расширения CurrentVersion не может быть применена к вашему вложенному запросу! Вы можете использовать его только с помощью простых запросов, таких как Db.Groups.Текущая версия(); Для сложных нужно использовать Db.Groups.SelectMany (p => p.GroupMembers.AsQueryable(). Где (ExpressionsHelper.CurrentVersion (дата))); Метод расширения представлен только как образец - если вы хотите его использовать, вы можете получить его без дублирования кода. – mr100

Смежные вопросы