订购linq查询

时间:2009-05-27 08:51:00

标签: c# linq-to-sql

对于我的通用网格,我目前这样做是为了激活排序:

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执行。

现在,当然column.SortExpression应该是另一种类型。只有我无法确定它应该是什么类型以及如何在控制器中的泛型类上设置它。

我仍然可以用某种通用的强类型方式设置SortExpression。

有关如何通过表达式在应用程序中的其他位置进行排序的任何建议,而不是在将顺序应用于IQueryable时执行sql?

@Ewwicker:

这有效:

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 个答案:

答案 0 :(得分:3)

SortExpression的类型应为Expression<Func<T, object>>

通过使其为Func<T, object>,您可以使编译器将其直接减少到IL,准备执行。 Linq to SQL(或实体,或NHibernate,或其他)将需要以表达式树的形式捕获的代码,以便它可以将其转换为SQL或其他一些查询语言以便在其他地方执行。通过将lambda分配给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 :(得分:1)

我提出了一个解决方案来实现我的目标。

用法:在列上设置强类型排序表达式:

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)
            }
          };

基础代码

类RainbowGridBuilder中的“buildGrid()”方法中的这几行应用排序:

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,它搜索非null的私有成员并相应地进行排序:

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>”。

答案 2 :(得分:0)

我认为问题的根源在于您在转换为Queryable之前执行了OrderBy 这一事实。如果您在IEnumerable&lt; T&gt;上订购,那么您需要先订购一些东西。与IQueryable&lt; T&gt;不同,IEnumerable&lt; T&gt;不构建表达式树...它包围一个可枚举的另一个。要获得延迟执行的好处,您需要确保从一开始就使用IQueryable。在您执行了所有过滤,排序等之后转换为一个将不会带来任何好处。

答案 3 :(得分:0)

以下是我对此顺序问题的简单解决方案:

        var SampleData = new SampleDataContext();

        var text = from i in SampleData.Events
                   select i;
        var text2 = text.OrderByDescending(i => i.id);
        return View(text2);