【问题标题】:LINQ/LINQ-to-SQL: Is there a way to generate the SQL using a combined "where" filter?LINQ/LINQ-to-SQL:有没有办法使用组合的“where”过滤器生成 SQL?
【发布时间】:2010-11-23 22:02:46
【问题描述】:

我正在尝试设置一个查询界面,用户可以在其中选择任意一组过滤器以最终从数据库中获取数据。我遇到的问题是 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);
}

当我运行它时,我的结果集是我所期望的(即用户名 = "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 做一些它不打算做的事情?

【问题讨论】:

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


    【解决方案1】:

    您正在使用IEnumerable&lt;T&gt; - 这几乎仅限于处理数据本地,一旦通过LogoutTime 上的单个.Where(...) 实现;查询组合需求 IQueryable&lt;T&gt;。反过来,每个谓词都需要Expression&lt;Func&lt;Session, bool&gt;&gt;

    试试:

    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&lt;Session, bool&gt; 委托,则需要通过 Expression&lt;Func&lt;Session, bool&gt;&gt; 将其更新为表达式树。

    【讨论】:

    • 那行得通。非常感谢!你的解释也有帮助,因为我想知道 IQueryable 和 IEnumerable 之间的区别(我刚刚发现了表达式)。
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      使用 IQueryable 代替 IEnumerable

      【讨论】:

        猜你喜欢
        • 2021-12-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-16
        • 1970-01-01
        相关资源
        最近更新 更多