Linq - как я могу использовать функцию в запросе - PullRequest
0 голосов
/ 24 октября 2011

Я использую C # на WP7 (Mango).Я пытаюсь использовать специальный запрос, потому что получаю сообщение об ошибке:

Метод 'Int32 orderBirthday (System.DateTime)' не поддерживает перевод в SQL.

Да,Я знаю ... Linq не может использовать мою функцию, но я не знаю правильный путь ...

У меня есть таблица базы данных со столбцами name и birthday.В моем запросе я вычислю, сколько дней будет до следующего дня рождения (из всех предметов), а затем я закажу «по убыванию».

static int orderBirthday(DateTime Birthday)
    {
        DateTime today = DateTime.Today;
        DateTime birthday = Birthday;
        DateTime next = new DateTime(today.Year, birthday.Month, birthday.Day);

        if (next < today)
            next = next.AddYears(1);

        int numDays = (next - today).Days;

        // No Conversion
        return numDays;
    }

 public void LoadCollectionsFromDatabase()
    {

        DateTime today = DateTime.Today;

        var toDoItemsInDB = from ToDoItem todo in toDoDB.Items
                            let daysToBirthday = orderBirthday(todo.ItemDate)
                            orderby daysToBirthday ascending
                            select todo;

        // Query the database and load all to-do items.
        AllToDoItems = new ObservableCollection<ToDoItem>(toDoItemsInDB);
.
.
.
}

Ответы [ 4 ]

1 голос
/ 24 октября 2011

Вы должны либо извлечь все из базы данных и отсортировать ее локально (как показывает Enigmativity), либо найти способ выразить операцию сортировки в самом операторе LINQ. А поскольку вы извлекли поведение сортировки в свою собственную функцию, вы, вероятно, захотите повторно использовать эту логику. В этом случае лучше всего создать функцию, которая фильтрует IQueryable.

Вот пример того, как это сделать:

public static IOrderedQueryable<Item> OrderByBirthday(
    this IQueryable<Item> items)
{
    return
        from item in items
        let today = DateTime.Today
        let birthday = item.ItemDate
        let next = new DateTime(today.Year, birthday.Month, birthday.Day)
        let next2 = next < today ? next.AddYears(1) : next
        orderby (next - today).Days
        select item;
}

Вы можете использовать метод следующим образом:

var toDoItemsInDB = OrderByBirthday(toDoDB.Items);

Или вы можете использовать его как метод расширения:

var toDoItemsInDB = toDoDB.Items.OrderByBirthday();
0 голосов
/ 24 октября 2011

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

0 голосов
/ 24 октября 2011

Два способа:

Один: перетащите его из Linq2SQL в объекты Linq2Object, используя ToEnumerable(), а затем используйте orderBirthday на уровне C #.

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

Два: написать эквивалентную функцию в SQL, скажем, она называлась dbo.orderBirthday. MakeВаш orderBirthday метод является нестатическим методом вашего класса, полученного из datacontext, а затем пометьте ваш метод как эквивалентный функции SQL:

[Function(Name="dbo.orderBirthday",IsComposable=true)] //IsComposable is true for functions that can be used within queries, false for stored procedures that must be called on their own.
public int OrderBirthday([Parameter(Name="@birthday",DbType="datetime") DateTime birthday)
{
    return Helper.OrderBirthday(birthday); // just to show that we can keep the static version around if we want and call into it. Alternatively we could just move the whole body here.
}

Здесь код C # используется в не-Linq2SQL-контекстеи код SQL используется при составлении запроса SQL в контексте Linq2SQL.

Преимущество: может дольше оставаться в SQL. Недостаток: две версии одного и того же метода могут не синхронизироваться и вызывать ошибки.

Также возможно, чтобы код C # постоянно вызывал код SQL:

[Function(Name="dbo.orderBirthday",IsComposable=true)]
public int OrderBirthday([Parameter(Name="@birthday",DbType="datetime") DateTime birthday)
{
    return (int)ExecuteMethodCall(this, (MethodInfo)MethodInfo.GetCurrentMethod(), birthday).ReturnValue;
}

Преимущество: одна версия (SQL) остается единственной версией, поэтому она не может выпастьсинхронизации с версией C #.Недостаток: вызывает SQL даже при работе с объектами, которые не имеют ничего общего с SQL.

0 голосов
/ 24 октября 2011

Это просто, если вы сделаете это:

    var toDoItemsInDB = from ToDoItem todo in toDoDB.Items.ToArray()
                        let daysToBirthday = orderBirthday(todo.ItemDate)
                        orderby daysToBirthday ascending
                        select todo.;

Обратите внимание на .ToArray(), добавленное к Items. Вы в основном вносите результаты в память, и ваша функция может работать.

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