Добавление функции к объектам Linq-to-SQL для выполнения общих выборов - PullRequest
2 голосов
/ 16 октября 2008

В предыдущем вопросе я спросил, как сделать «Вычисляемые свойства» в объекте linq to sql. Ответа, предоставленного там, было достаточно для этого конкретного случая, но теперь я столкнулся с аналогичным препятствием в другом случае.

У меня есть база данных с Предметами , которые должны пройти через Шаги . Я хочу, чтобы в моей базе данных была функция, которая извлекает текущий шаг элемента, который я затем могу построить. Например:

var x = db.Items.Where(item => item.Steps.CurrentStep().Completed == null);

Код для получения текущего шага:

Steps.OrderByDescending(step => step.Created).First();

Поэтому я попытался добавить метод расширения к EntitySet , который вернул один Шаг , например:

public static OrderFlowItemStep CurrentStep(this EntitySet<OrderFlowItemStep> steps)
{
    return steps.OrderByDescending(o => o.Created).First();
}

Но когда я пытаюсь выполнить запрос сверху, я получаю сообщение о том, что функция CurrentStep () не переводится в SQL. Есть ли способ добавить эту функциональность в Linq-to-SQL каким-либо образом, или мне приходится каждый раз вручную писать запрос? Сначала я попытался выписать весь запрос, но он очень длинный, и если я когда-нибудь изменю способ получения активного шага элемента, мне придется снова просмотреть весь код.

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

Ответы [ 2 ]

1 голос
/ 19 октября 2008

Проблема в том, что CurrentStep - это обычный метод. Следовательно, выражение содержит вызов этого метода, и, естественно, SQL не может выполнять произвольные методы .NET.

Вам нужно будет представить код как выражение. У меня есть один пример глубины здесь: http://www.atrevido.net/blog/2007/09/06/Complicated+Functions+In+LINQ+To+SQL.aspx

К сожалению, компилятор C # 3.0 имеет огромное упущение, и вы не можете генерировать вызовы для выражений. (т.е. вы не можете написать "x => MyExpression (x)"). Чтобы обойти это, нужно либо написать выражение вручную, либо использовать делегат в качестве заполнителя. У Джомо Фишера есть интересный пост о манипулировании деревьями выражений в целом.

На самом деле, не делая этого, я бы, вероятно, подошел к этому, заставив функцию CurrentStep принять предикат, который вы хотите добавить ("Completed == null"). Затем вы можете создать полный Expression> предикат для передачи в Where. Я ленивый, поэтому я собираюсь сделать пример, используя String и Char (String содержит символы, как Item содержит шаги):

using System;
using System.Linq;
using System.Linq.Expressions;

class Program {
    static void Main(string[] args) {
        Console.WriteLine(StringPredicate(c => Char.IsDigit(c)));
        var func = StringPredicate(c => Char.IsDigit(c)).Compile();
        Console.WriteLine(func("h2ello"));
        Console.WriteLine(func("2ello"));
    }

    public static Expression<Func<string,bool>> StringPredicate(Expression<Func<char,bool>> pred) {
        Expression<Func<string, char>> get = s => s.First();
        var p = Expression.Parameter(typeof(string), "s");
        return Expression.Lambda<Func<string, bool>>(
            Expression.Invoke(pred, Expression.Invoke(get, p)),
            p);
    }
}

Таким образом, «func» создается с помощью StringPredicate для создания выражения. Для примера мы скомпилируем его для локального выполнения. В вашем случае вы передали бы весь предикат в «Где», чтобы он был переведен в SQL.

Выражение «get» - это место, где вы помещаете свои «расширения» (OrderByWh независимо, First и т. Д.). Затем это передается предикату, который вам дан.

Не волнуйтесь, если это выглядит сложно; это Сорта на первых порах. Если вы раньше не делали такого рода вещи, это займет немного времени (в первый раз, когда я делал такие вещи, потребовались часы, чтобы сделать это правильно: | .. теперь это немного легче). Кроме того, как я уже упоминал, вы можете написать вспомогательный метод, чтобы сделать это переписывание для вас (так что вам не нужно напрямую использовать Expression.Wh независимо от методов), но я не видел примеров и не нужно было еще.

0 голосов
/ 17 октября 2008

Проверьте мой ответ на " оператор переключения в linq " и посмотрите, указывает ли это в правильном направлении ...

Техника, которую я демонстрирую, есть та, которая заставила меня преодолеть страшную ошибку "нет перевода на SQL".

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