Методы обхода использования пользовательских методов / методов расширения в LINQ to Entities - PullRequest
9 голосов
/ 01 февраля 2011

Я определил класс GenericRepository, который выполняет взаимодействие с БД.

 protected GenericRepository rep = new GenericRepository();

И в моих классах BLL я могу запросить в БД:например, AccessLevel=5 => AccessLevel.BinaryAnd(5) и AccessLevel.binaryAnd(1) оба возвращают true.

Однако я не могу использовать этот метод расширения в моих запросах LINQ.Я получаю ошибку времени выполнения следующим образом:
LINQ to Entities does not recognize the method 'Boolean BinaryAnd(System.Object, System.Object)' method, and this method cannot be translated into a store expression.

Также попытался изменить его на пользовательский метод, но безуспешно.Каковы обходные пути?

Должен ли я получить все альбомы и затем повторить их через цикл foreach и выбрать те, которые соответствуют AccessLevels?

Ответы [ 3 ]

8 голосов
/ 23 мая 2012

Я понимаю, что у этого уже есть принятый ответ, я просто думал опубликовать его на тот случай, если кто-то захочет написать перехватчик выражений LINQ.

Итак ... вот что я сделал, чтобы сделать переводимые методы расширения: Пример кода

Я не считаю, что это законченное решение, но, надеюсь, оно должно послужить хорошей отправной точкой для всех, кто достаточно смел, чтобы довести его до конца.

7 голосов
/ 01 февраля 2011

Вы можете использовать только основные методы расширения и методы CLR, определенные для вашего поставщика EF при использовании Entity Framework и запросах на IQueryable<T>. Это связано с тем, что запрос транслируется непосредственно в код SQL и выполняется на сервере.

Вы можете выполнить потоковую передачу всей коллекции (используя .ToEnumerable()), а затем запросить ее локально или преобразовать ее в метод, который может быть переведен непосредственно в SQL вашим поставщиком.

При этом поддерживаются базовые побитовые операции :

Битовые операторы AND, OR, NOT и XOR также отображаются в канонические функции, когда операнд является числовым типом.

Итак, если вы переписываете это, чтобы не использовать метод, а просто выполняли побитовую операцию со значением напрямую, оно должно работать по мере необходимости. Попробуйте что-то вроде следующего:

public List<Album> GetVisibleAlbums(int accessLevel)
{
    return rep.Find<Album>(a => (a.AccessLevel & accessLevel > 0)).ToList();  
}

(Я не уверен точно, как работает ваш текущий метод расширения - вышеизложенное проверит, чтобы увидеть, вернется ли какой-либо из флагов в соответствие с вашим утверждением ...)

1 голос
/ 01 февраля 2011

Существуют способы изменить запрос linq непосредственно перед тем, как EF переведет его в SQL, в этот момент вам нужно будет перевести свой «чужой» метод в конструкцию, переводимую EF.

См. Мой предыдущий вопрос Как обернуть Entity Framework для перехвата выражения LINQ непосредственно перед выполнением? и мое расширение EFWrappableFields , которое делает это только для перенесенных полей.

...