Заказать запрос linq - PullRequest
3 голосов
/ 27 мая 2009

Для моей общей сетки я сейчас делаю это, чтобы активировать сортировку:

Elements.OrderBy(column.SortExpression).AsQueryable();

В котором SortExpression имеет тип Func<T, object>, а столбец является универсальным классом Column<T>

Я установил SortExpression в контроллере следующим образом:

new Column<OrderViewData>{Key = "ShippingDate", SortExpression = e => e.ShippingDate}

OrderBy вызывает выполнение оператора sql, который мне не нужен.

Итак, я пытаюсь заменить его на это:

Elements = from element in Elements
           orderby column.SortExpression
           select element;

Что не запускает выполнение sql.

Теперь, конечно, столбец. Выражение сортировки должно быть другого типа. Только я не могу понять, какого типа он должен быть и как установить его в универсальный класс в контроллере.

Я все еще должен быть в состоянии установить SortExpression в некотором роде в строгом стиле.

Любые предложения о том, как я могу заказать с помощью набора выражений где-то еще в приложении, без выполнения SQL при применении заказа к IQueryable?

@ Earwicker:

Это работает:

Expression<Func<Employee, DateTime?>> sortexpression = e => e.BirthDate;
var db = new NorthwindDataContext();
var query = from e in db.Employees
            select e;
query = query.OrderBy(sortexpression);
int count = query.Count();

и генерирует:

SELECT COUNT(*) AS [value]
FROM [dbo].[Employees] AS [t0]

Когда я заменю DateTime? в первой строке с объектом:

Expression<Func<Employee, object>> sortexpression = e => e.BirthDate;

Я получаю исключение InvalidOperationException: невозможно оформить заказ по типу 'System.Object'

Теперь вы можете сказать: «тогда просто использовать DateTime?», Но я бы хотел построить столбцы в моей общей сетке, чтобы потребовать как можно меньше кода. Я не хочу, чтобы люди печатали все Expression<Func<Employee, some_type>>. Я хочу, чтобы люди могли просто напечатать что-нибудь маленькое, например, мою первую попытку SortExpression = e => e.BirthDate, где я использую универсальный класс Column для определения 'T'.

Как вы думаете, было бы возможно создать какое-то расширение, которое каким-то образом получит тип e.BirthDate и затем преобразует Func<T, object> в Expression<Func<T,some_type>>? Тогда я мог бы сделать что-то во внутреннем коде, например: Elements.OrderBy (column.SortExpression.FixCast ())

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

Большое спасибо за помощь!

@ earwicker 2:

var gridBuilder = new RainbowGridBuilder<Employee>("Examples_Employees")
{
    Elements = GetEmployees(), //The elements (records) we will show in our grid. 

    //Define the columns for our grid.
    Columns = new List<Column<Employee>>{
            new Column<Employee> {
                Key = "EmployeeId",                             //Key is used for sorting, selecting columns, ...
                Header = "Employee Id",                         //The header of the column. Also used as caption in the column selection checkboxlist.
                ValueExpression = e => e.EmployeeID.ToString(), //The Linq expression which will be executed on each element to fill the cell
                SortExpression = e => e.EmployeeID,             //The Linq expression by which to sort the elements in the grid. 
                Display = false},                               //Is this column visible by default?
            new Column<Employee> {Key = "Name", ValueExpression = e => e.FirstName + " " + e.LastName, SortExpression = e => e.LastName},
        },

    // Some other properties here that are irrelevant.


}

Ответы [ 4 ]

3 голосов
/ 27 мая 2009

SortExpression должно иметь тип Expression<Func<T, object>>.

Делая его Func<T, object>, вы заставляете компилятор сократить его прямо до IL, готового к выполнению. Linq to SQL (или объектам, или NHibernate, или какому-либо другому) понадобится код, захваченный в форме дерева выражений, чтобы он мог перевести его на SQL или другой язык запросов для выполнения в другом месте. Назначая лямбду на Expression<Func<...>>, вы запускаете компиляцию в дереве выражений.

Это работает, если поставить это?

Elements = Elements.OrderBy(e => e.ShippingDate);

А как насчет этого?

Expression<Func<OrderViewData, object>> sortExpression = e => e.ShippingDate;
Elements = Elements.OrderBy(sortExpression);

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

Трудно понять, что было бы для вас идеальным вариантом, но в исходном коде настройки у вас было:

new Column<OrderViewData>{Key = "ShippingDate", SortExpression = e => e.ShippingDate}

Предположим, Column принял два параметра типа: TElem (тип значения, хранящегося в столбце) и TSort (тип значения для сортировки).

new Column<Employee, DateTime?> { SortExpression = e => e.BirthDate }

Это не выглядит слишком громоздким для меня, и тогда SortExpression будет просто:

Expression<Func<TElem, TSort>> SortExpression { get; set; }
1 голос
/ 01 июня 2009

Я нашел решение, которое позволяет достичь того, чего я добился.

Использование: Установка сильного типизированного выражения на столбцах:

Columns = new List<Column<Employee>>{
            new Column<Employee> {
                Key = "EmployeeId",   
                SortExpression = new SortExpression<Employee>(e => e.EmployeeID)
                // ... other irrelevant column properties ...  
            },
            new Column<Employee> {
                Key = "EmployeeBirthDate",      
                SortExpression = new SortExpression<Employee>(e => e.BirthDate)
            }
          };

Базовый код

Эти несколько строк в методе buildGrid () класса RainbowGridBuilder применяют сортировку:

if (columnToSort != null) //sort the elements according to the set column key and the sortexpression
{
    var column = Columns.Where(c => c.Key == columnToSort).SingleOrDefault();
    if (column != null)
    {
        Elements = column.SortExpression.ApplySortExpression(Elements, descending);
    }
}

Как это работает:

Посредством использования перегруженных конструкторов в классе SortExpression, который я сделал, я могу установить приватное Expression<Func<T, some_specific_Type>>.

Внутри класса SortExpression есть метод ApplySortExpression, который ищет ненулевой закрытый член и сортирует соответственно:

public class SortExpression<T>
{
    private Expression<Func<T, DateTime?>> DateTimeExpression { get; set; }
    private Expression<Func<T, int?>> intExpression { get; set; }
    private Expression<Func<T, string>> stringExpression { get; set; }

    public SortExpression(Expression<Func<T, DateTime?>> expression)
    {
        DateTimeExpression = expression;
    }

    public SortExpression(Expression<Func<T, int?>> expression)
    {
        intExpression = expression;
    }

    public SortExpression(Expression<Func<T, string>> expression)
    {
        stringExpression = expression;
    }

    public IQueryable<T> ApplySortExpression(IQueryable<T> elements, bool? descending)
    {
        if (DateTimeExpression != null)
        {
            if (descending.HasValue && descending.Value)
                return elements.OrderByDescending(DateTimeExpression);
            else
                return elements.OrderBy(DateTimeExpression);
        }
        else if (intExpression != null)
        {
            if (descending.HasValue && descending.Value)
                return elements.OrderByDescending(intExpression);
            else
                return elements.OrderBy(intExpression);
        }
        else if (stringExpression != null)
        {
            if (descending.HasValue && descending.Value)
                return elements.OrderByDescending(stringExpression);
            else
                return elements.OrderBy(stringExpression);
        }
        else
            throw new Exception("Unsuported sortkey type");
    }
}

Это решение может быть не очень чистым под капотом, но это удобство, которое я использовал после. Единственным изменением в коде потребления было добавление "new SortExpression<Employee>".

0 голосов
/ 14 ноября 2013

Вот мое простое решение этой проблемы заказа:

        var SampleData = new SampleDataContext();

        var text = from i in SampleData.Events
                   select i;
        var text2 = text.OrderByDescending(i => i.id);
        return View(text2);
0 голосов
/ 28 мая 2009

Я думаю, что корень проблемы связан с тем, что вы сделали OrderBy до преобразования в Queryable. Если вы заказываете на IEnumerable , то сначала нужно что-то заказать. В отличие от IQueryable , IEnumerable не создает деревья выражений ... он оборачивает одно перечисляемое вокруг другого. Чтобы воспользоваться преимуществами отложенного выполнения, вам необходимо убедиться, что вы работаете с IQueryable с самого начала. Преобразование в единицу после того, как вы выполнили всю фильтрацию, сортировку и т. Д., Не принесет никакой пользы.

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