Продвинутая сортировка Linq C # - PullRequest
3 голосов
/ 26 сентября 2011

У меня есть IQueryable, в котором есть список страниц.

Я хочу сделать: Pages.OrderByDescending(o => CalculateSort(o.page));

метод вычисления sort аналогичен простой английской версии:

public int calculatesort(page p)
{
    int rating = (from r in db.rating select r). sum();
    int comments = //query database for comments;

    float timedecayfactor = math.exp(-page.totalhoursago);

    return sortscore = (rating +comments)* timedecayfactor;
}

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

Как я могу сделать приведенную выше функцию понятной для sql, чтобы использовать ее для сортировки страниц?

Разве это не хороший подход для больших данных? Есть ли другой метод, используемый для сортировки наборов результатов, отличных от динамического в базе данных?

Я не спал несколько дней, пытаясь исправить это: (

Ответы [ 5 ]

2 голосов
/ 26 сентября 2011

ваш код далеко не компилируется, так что я многое здесь угадываю, но надеюсь, что это даёт идею.Как уже писали несколько, вам нужно дать Linq-2-Sql дерево выражений.Используя синтаксис запроса, вот что происходит (по волшебству компилятора)

                     from p in pages
                     let rating = (from r in db.rating
                                   where r.PageId == p.PageId
                                   select r.Value).Sum()
                     let comments = (from c in db.Comments
                                     where c.PageId == p.PageId
                                     select 1).Count()
                     let timedecayfactor = Math.Exp(-(p.totalhoursago))
                     orderby (rating + comments)*timedecayfactor descending
                     select p;

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

2 голосов
/ 26 сентября 2011

Ошибка возникает из-за того, что LINQ не может преобразовать пользовательский код / ​​методы в SQL. Он может конвертировать только Expression<Func<>> objects в SQL.

В вашем случае у вас есть сложная логика для сортировки, поэтому имеет смысл сделать это с помощью Stored Procedure, если вы хотите сделать это на уровне БД.

Или загрузите все объекты в основную память и запустите метод вычисления сортировки для объектов в памяти

РЕДАКТИРОВАТЬ:

У меня нет кода, поэтому лучшее, что я могу сделать, это описать по-английски:

  • Иметь таблицу со структурой, способной временно хранить все текущие данные пользователей.
  • Иметь вычисляемое поле в таблице страниц, содержащее значение, рассчитанное по всем не относящимся к пользователю полям
  • Напишите хранимую процедуру, которая использует значения из этих двух источников (временная таблица и поле calc) для фактической сортировки.
  • Удалить временную таблицу как последнюю часть сохраненного процесса
  • Вы можете прочитать о сохраненных процессах здесь и здесь
0 голосов
/ 26 сентября 2011

Да, считая предыдущие ответы: LINQ to SQL не знает, как перевести метод CalculateSort. Вы должны преобразовать LINQ в SQL в обычный LINQ to Object перед использованием пользовательского метода.

Попробуйте использовать это при вызове CalculateSort, добавив AsEnumerable:

Pages.AsEnumerable().OrderByDescending(o => CalculateSort(o.page));

Тогда вы можете использовать метод расширения OrderByDescending.

UPDATE: LINQ to SQL всегда переводит запрос в коде в дерево выражений. Это почти та же концепция, что и AST любого языка программирования. Эти деревья выражений затем переводятся в выражения SQL, специфичные для SQL Server SQL, поскольку в настоящее время LINQ to SQL поддерживает только SQL Server 2005 и 2008.

0 голосов
/ 26 сентября 2011
var comments = db.comments.Where(...);
Pages.OrderByDescending(p=>(db.rating.Sum(r=>r.rate) + comments.Count()) * Math.Exp(-p.totalhoursago))
0 голосов
/ 26 сентября 2011

Linq ожидает, что Calculatesort вернет «запрашиваемое» выражение, чтобы сгенерировать собственный SQL.

In может встроить ваш метод «calclatesort» в это лямбда-выражение.(Я заменил ваши переменные на константы для компиляции в моей среде)

public static void ComplexSort(IQueryable<string> Pages)
{
    Pages.OrderByDescending(p =>
        {
            int rating = 99;//(from r in db.rating select r). sum();
            int comments = 33;//query database for comments;
            double timedecayfactor = Math.Exp(88);
            return (rating + comments) * timedecayfactor;
        });
}

Кроме того, вы можете даже попытаться запустить это параллельно (начиная с .net 4.0), заменив первую строку на

    Pages.AsParallel().OrderByDescending(p =>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...