Как создать метод, который поддерживает перевод в SQL? - PullRequest
8 голосов
/ 05 октября 2010

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

return manager.Clients.SelectAll().Where(cli => cli.Name.SatisfyFilter(filter.Name) && cli.LastName.SatisfyFilter(filter.LastName) && cli.MiddleName.SatisfyFilter(filter.MiddleName)).ToList();

Но я получаю:

"У метода 'Boolean SatisfyFilter (System.String, System.String)' нет поддерживаемого перевода в SQL."

Error

Мой метод:

public static bool SatisfyFilter(this string palavra, string filtro)

то же самое, что и

public bool Contains(string value)

в строковом типе, и Contains прекрасно работает ...

Мне нужен этот метод для запуска на IQueryable, потому что в моей таблице 25 миллионов клиентов ...

Я видел на профилировщике sql, что Contains преобразуется в sql ...

Как мне реализовать мой метод отправки кода соответствующего фильтра в sql? = /

Ответы [ 6 ]

8 голосов
/ 05 октября 2010

Создайте пользовательскую функцию на вашем SQL-сервере, которая будет эквивалентна вашему C # -коду.Скажем, он назывался "dbo.SatsFilter".

Создайте метод для переопределения текста данных, скажем, что он выглядит следующим образом:

public bool SatisfiesFilter(string name, string filter)
{
  // some sort of implementation.
}

Украсьте метод C # с помощью [Function] и [Parameter]атрибуты, поэтому он выглядит примерно так:

[Function(Name="dbo.SatsFilter",IsComposable=true)]
public bool SatisfiesFilter([Parameter name="@name",DbType="nvarchar(50)"]string name, [Parameter name="@filter",DbType="nvarchar(50)"]string filter)

IsComposable=true означает, что это функция, а не хранимая процедура, и, следовательно, может использоваться как часть более крупного запроса.

Вы можетеТеперь используйте этот метод DataContext, и он будет при необходимости преобразован в SQL, или C # будет использоваться в запросах, выполняемых в памяти.

Обратите внимание также, что если вы хотите использовать SQL все время(иногда полезно) вы могли бы вызывать в SQL, когда метод вызывается из кода C #:

[Function(Name="dbo.SatsFilter",IsComposable=true)]
public bool SatisfiesFilter([Parameter name="@name",DbType="nvarchar(50)"]string name, [Parameter name="@filter",DbType="nvarchar(50)"]string filter)
{
  return (bool)ExecuteMethodCall(this, (MethodInfo)MethodInfo.GetCurrentMethod(), name, filter).ReturnValue;
}

Это не очень полезно, когда эквивалент C # удобен, так как это означает попадание в базу данных и некоторыеперевод, но это полезно, если пользовательская функция зависит от состояния базы данных или ее трудно хорошо перевести на C #

4 голосов
/ 05 октября 2010

Простой ответ: Вы не можете .Переводчик LINQ to SQL распознает только некоторые из стандартных методов .NET, и вы не сможете добавить другие.

  • Если вам нужно что-то подобное, вам нужно создать выражениедерево явно (для использования в качестве тела лямбда-выражения).Прямой способ сделать это - использовать методы класса Expression, но это может быть значительно упрощено.

  • Возможно, лучшим вариантом будет использование проекта LINQKit .Это позволяет вызывать другие лямбда-выражения (не совсем метод, но близкий).Он предоставляет метод расширения AsExpandable, который позволяет писать:

    Expression<Func<Purchase, bool>> customFunction = ...
    var data = new MyDataContext();
    var query =
      from c in data.Purchases.AsExpandable()
      where customFunction.Compile()(c)
      select c.Name;
    

    customFunction - это лямбда-функция, скомпилированная в виде дерева выражений, и вы можете использовать ее внутри запроса.Расширение AsExpandable заменяет использование телом функции, поэтому с этим может справиться транслятор LINQ to SQL.Подробнее о том, как это работает, можно прочитать в моем блоге .

  • Другой альтернативой, более подробно обсуждаемой другими, является реализация функциональности в качестве пользователя SQL.определенная функция.Затем вы можете перетащить функцию в свой контекст данных и вызвать функцию из запроса.Переводчик просто вставит вызов вашей функции SQL.

1 голос
/ 20 декабря 2018

хорошее решение,

Объявление свойств класса, которые можно преобразовать для удаленного выполнения LINQ с помощью Microsoft.Linq.Translations

примеры

Пакет NuGet

Источник на GitHub

1 голос
/ 05 октября 2010

Вы делаете две вещи:

  1. Создать пользовательскую скалярную функцию в SQL: http://msdn.microsoft.com/en-us/library/bb386973.aspx
  2. Называйте это как хотите в Linq To SQL: http://msdn.microsoft.com/en-us/library/bb399416.aspx
1 голос
/ 05 октября 2010

Если вы можете сопоставить это с udf, вы можете перетащить udf в data-contextx. При обращении через контекст данных LINQ-to-SQL может выполнить перевод.

Если вы просто фильтруете iqueryable, вы можете написать метод, который просто использует Where (возвращает новый iqueryable), который может хорошо работать.

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

0 голосов
/ 05 октября 2010

Самый простой способ сделать это - выяснить, как преобразовать вашу функцию 'SatisfyFilter' в серию команд linq с принятым переводом.Боюсь, что на самом деле не существует другого «простого» способа использования вашей пользовательской функции без фильтрации 25 миллионов клиентов до более материализуемого числа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...