将 Linq 查询部分插入到现有查询中。

3

有以下变量,存储了一个 IQueryable

var mainQuery = session
    .Query<Employee>()
    .Select(e => new
    {
        e.Name,
        e.Address
    });

同时,需要一个以IQueryable作为参数的方法。

public DataTable GetData(IQueryable query)
{
    ...
}

我该如何在GetData()内部编写代码,以在Select()之前添加OrderBy()

query的最终值应该看起来像是使用以下Linq表达式构建的:

var query = session
    .Query<Employee>()
    .OrderBy(e => e.Age)
    .Select(e => new
    {
        e.Name,
        e.Address
    });

这是必需的,因为如果我在Select()之后添加OrderBy(),那么我只能按匿名类型(名称、地址)的成员进行排序。如果一个雇员还有年龄,那么当我把OrderBy()放在Select()之后时,我无法按年龄排序。
更新: GetData对查询的结构一无所知,除了它以Select结束。 而且它必须具有确切的签名public DataTable GetData(IQueryable query)-没有额外的参数。
需要修改方法内部的现有查询,并在Select之前添加OrderBy
当有正确答案时,我会接受并投票支持。
2个回答

3
为什么不在调用 GetData() 后应用 select()
var mainQuery = session.Query<Employee>();

this.GetData(mainQuery);

mainQuery.OrderBy(x => x.Age)
         .Select(x => new
                 {
                     x.Name,
                     x.Address
                 });

Linq表达式树是不可变的(来源)。你必须分部创建树的副本以进行修改。
更新:请记住,您的模式试图将数据访问与表示分离(或者至少是这样读取的)。排序是一种表示方式。您可能有多个客户端想要使用GetData获取数据,但每个客户端可能希望以不同的方式对数据进行排序。您原始的查询在调用GetData之后进行了投影,因此使用投影排序是有意义的。
现在,如果您真的想在方法内部排序而不更改其合同,则必须遍历linq查询的表达式树,并从头开始重建它,在正确的位置注入排序。表达式树是不可变的,无法就地修改。

我可以这样做,但这不是问题的所在。考虑将GetData内的查询修改为合同 - 添加OrderBy必须在那里完成。如果你所回答的可以实现,那就不会有任何问题了。 - Răzvan Flavius Panda
我不确定GetData负责对数据进行排序是否有意义。如果在上述情况中,将select放在GetData之外是有效的,则在那里进行排序也是有意义的。GetData应只负责获取数据。排序仅是表示问题,应与您的select一起处理。如果您有多个调用者调用GetData,则每个调用方期望按不同方式对数据进行排序可能是有意义的。这就是为什么排序是表示问题,并应该由上一级处理。 - Jordan Parmer
GetData()只是我随意选的一个名称,它是由ObjectDataSource使用的方法,因此需要在其中进行分页/排序。如果我在投影之后使用OrderBy,则无法按Employee的任何字段进行排序,例如AgeSelect之后不可用于排序。重建表达式树正是我所寻找的,我不知道IQueryable是不可变的。对于增加的价值+1,您说了如何做,但是在非常高的层面上 :) - Răzvan Flavius Panda

2
考虑为“Employee”创建“ViewModel”或“DTO”,而不是传递匿名对象。但是,您仍然可以将“selector”传递到“GetData”中,在对“Employee”进行排序后应用它。
var mainQuery = session.Query<Employee>();

GetData(mainQuery, e => new { e.Name, e.Address });

//object is used because you create anonymous objects and pass them around
public DataTable GetData(IQueryable query, 
                         Expression<Func<Employee, object>> selector)
{
    return query.OrderBy(e => e.Age)
                .Select(selector)
                //...
}

1
似乎你的方法不正确,你应该获取一个 Expression<Func<Employee, object>>。 - hackp0int
@lamStalker 感谢您的留言。我的 EF 版本也支持 Func,但是在使用 Expression 时生成的 sql 是经过优化的。 - Ilya Ivanov
没问题,帮助你是我的荣幸。 - hackp0int
@IlyaIvanov:这并没有回答问题,因为它修改了“GetData”的签名。 - Răzvan Flavius Panda

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接