LINQ / LINQ-to-SQL:有没有办法使用组合的“where”过滤器生成SQL?

时间:2010-11-23 22:02:47

标签: .net sql linq linq-to-sql

我正在尝试设置一个查询界面,用户可以选择一组任意过滤器来最终从数据库中获取数据。我遇到的问题是LINQ-to-SQL要么不像我期望的那样,要么我做错了,因为我的第一个限制WHERE条件是通过SQL传递的。其他过滤内容似乎正确发生,但是,据我所知,一旦数据被提取,就会发生这种情况。

这就是我想要做的事情。

我有一个使用Sessions表设置的数据库。我已经设置了我的LINQ-to-SQL映射内容,我通过过滤掉空注销时间以及用户可能指定的任何其他过滤器来获取“活动”会话:

public static IEnumerable<Session> GetSessions(params Func<Session, bool>[] filters)
{
    // I've created an auto-generate Linq-to-SQL context object with a Sessions table.
    using (DataSourceDataContext ctx = new DataSourceDataContext())
    {
        // Begin with all "active" sessions
        IEnumerable<Session> sessions = ctx.Sessions.Where(x => x.LogoutTime == null);
        foreach (var filter in filters)
            sessions = sessions.Where(filter);
        return sessions.ToArray();
    }
}

static void Main(string[] args)
{
    Func<Session, bool> mySessions = (x => x.UserName == "steven");
    IEnumerable<Session> sessions = GetSessions(mySessions);
}

当我运行它时,我的结果集就是我所期望的(即使用username =“steven”的活动会话),但是从SQL请求完整的活动会话列表(通过Profiler):

SELECT [t0].[ID], [t0].[UserName], [t0].[LoginTime], [t0].[LogoutTime], [t0].[Location]
FROM [dbo].[Sessions] AS [t0]
WHERE [t0].[LogoutTime] IS NULL

我的印象是LINQ将继续在幕后构建查询,直到我遍历我的集合,但我无法弄清楚为什么它没有为SQL部分做这些。我错过了什么,或者我只是想让LINQ-to-SQL做一些不打算做的事情?

3 个答案:

答案 0 :(得分:3)

您正在使用IEnumerable<T> - 这一点非常受限于在.Where(...)上由您的LogoutTime个体实现后,本地处理数据 ;查询合成要求 IQueryable<T>。反过来,每个谓词都需要Expression<Func<Session, bool>>

尝试:

public static Session[] GetSessions(
    params Expression<Func<Session, bool>>[] filters)
{
    // I've created an auto-generate Linq-to-SQL context object with
    // a Sessions table.
    using (var ctx = new DataSourceDataContext())
    {
        // Begin with all "active" sessions
        IQueryable<Session> sessions = ctx.Sessions
             .Where(x => x.LogoutTime == null);
        foreach (var filter in filters)
            sessions = sessions.Where(filter);
        return sessions.ToArray();
    }
}

您仍然可以使用 lambdas 来调用它,但是如果您明确处理Func<Session, bool>个委托,则需要通过Expression<Func<Session, bool>>将这些代理更新为表达式树。

答案 1 :(得分:2)

您将第一个ctx.Sessions.Where()语句的结果赋给变量IEnumerable<Session>。这会导致后续过滤操作在IEnumerable上使用Where扩展方法,而不是IQueryable。 Queryable.Where方法是Linq2SQL linq提供程序可以将过滤谓词(Expression&gt;类型)转换为实际SQL的方法.Enumerable.Where接受Func委托,并将在内存中进行过滤

答案 2 :(得分:1)

使用IQueryable而不是IEnumerable