【问题标题】:Linq and IEnumerable lazy query. Efficiency lost?Linq 和 IEnumerable 惰性查询。效率损失?
【发布时间】:2013-01-10 11:21:12
【问题描述】:

我一直在阅读 Ienumerables 不会立即运行。所以我试图找到查询列表的最佳方式。

下面是我的 getAll 方法。其次是我的过滤方法。其次是首选的过滤方法(可读性)。

我的问题是,第三种方法和直接查询一样吗?换句话说,它会,还是不会从数据库加载所有 myObjects 然后过滤?或者从数据库获取时进行过滤。

   public static IEnumerable<myObject> getAll()
    {
        using (var db = Database.OpenConnectionString(blahblah))
        {
            var queryResults = db.Query("SELECT * FROM vu_myObjects");

            return queryResults .Select(x => new myObject(x.myObjectName, x.myObjectF));
        }
    }

    public static IEnumerable<myObject> getAllForFilter(String filter)
    {
        using (var db = Database.OpenConnectionString(blahblah))
        {
            var queryResults  = db.Query("SELECT * FROM vu_myObjects WHERE ObjectF = @0", filter);

            return queryResults.Select(x => new myObject(x.myObjectName, x.ObjectF));
        }
    }

   public static IEnumerable<myObject> getAllForFilter(String filter)
    { // Not checked syntax.
        return getAll().Where(x => x.ObjectF = filter);
    }

或者,如果您有更好的建议,我会全力以赴。

【问题讨论】:

  • IQueryable 已推迟执行...

标签: c# performance linq ienumerable


【解决方案1】:

会,还是不会从数据库中加载所有 myObjects 然后过滤?

不会因为您还没有真正查询数据库。 IQueryable&lt;T&gt; 已延迟执行,因此为了实际返回结果集,您需要 执行 查询。这可以通过几种方式完成,例如调用ToList 或迭代列表。

任何过滤,即您的Where 子句,都将在数据库端完成。

实际上,您目前拥有的代码甚至无法正常工作 - 它会抛出 ObjectDisposedException,因为您试图在处理数据上下文之后 对延迟查询应用过滤器。要使您的代码正常工作,您需要将 where 子句作为参数传递给您的 getAll 方法,例如

public static IEnumerable<myObject> getAll(Expression<Func<myObject,bool>> where)
{
    using (var db = Database.OpenConnectionString(blahblah))
    {
        var queryResults = db.Query("SELECT * FROM vu_myObjects");
        if (where != null)
        {
            queryResults.Where(where);
        }
        return queryResults .Select(x => new myObject(x.myObjectName, x.myObjectF));
    }
}

public static IEnumerable<myObject> getAllForFilter(String filter)
{ // Not checked syntax.
    return getAll(x => x.ObjectF = filter);
}

更新

正如您刚刚指出的那样,您使用的是WebMatrix.Database,以上都不适用,因为这里没有延迟执行。 Query 方法立即执行并返回IEnumerable&lt;T&gt; 的结果集,因此任何过滤应用的后缀都将在内存中完成。所以就效率而言,第一种过滤方法会更好,因为它在数据库端完成所有操作。

您可以通过将Where 子句转换为实际字符串并将其附加到您的查询中来获得可读性和效率。

【讨论】:

  • 我应该提到using WebMatrix.Data; 是我使用的Database 对象。那是 IQueryable 吗?那么我推迟执行是真的吗?
  • 谢谢伙计。你的信息和想法帮助我产生了一些可读、有效的方法。谢谢。
  • 在分析时,DB 被击中db.Query() 那么我应该使用什么Database 类,以保持易于使用的API?
  • @Mcloving 我不确定你在这里问什么?
  • @Mcloving 看起来不错,我想一个小的改进是在方法签名中提供nullwhereparameters 默认值,这样您就可以调用该方法而无需指定自己的 null 值(您至少需要使用 C# 4.0 来执行此操作)。否则,您可以添加一个重载方法。另外,我建议在该方法中进行一些参数检查,并在必要时抛出适当的异常,即如果你有一个 where 子句,你的参数列表不应该为 null 或空等。
【解决方案2】:

它们基本上都是一样的。在您真正询问从 getAlLForFilter 调用返回的 IEnumerable 之前,它将是一个延迟评估的查询。如果您在其上调用 .ToList() 或访问内容,那么此时它将调用数据库。如果您在第 3 次调用中设置断点,您将看到它不会包含查询结果,直到您告诉调试器评估查询。

【讨论】:

  • 哦,其他人不这么认为:(
  • 我的错 - 我在考虑你使用 ORM - 正如@James 所说,如果你使用 IQueryable 代替,那会给你延迟执行
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-09
  • 1970-01-01
  • 2014-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-07
相关资源
最近更新 更多