【问题标题】:EntityFramework : does IQueryable or IEnumerable get all the results at the first place?EntityFramework:IQueryable 或 IEnumerable 是否首先获得所有结果?
【发布时间】:2012-10-09 23:04:58
【问题描述】:

我了解到 IQueryable 或 IEnumerable 数据类型一开始不会返回结果,仅在需要时才返回结果。但是,当我在手表检查器中打开该对象时,我看到所有对象都在那里。

我的代码有什么问题,还是因为我在手表上调用了它而显示?

[当我在监视对话框中查看 pendings 对象时,我看到了所有列表项,但它不应该首先加载。我的接近有什么问题,还是只是因为我在手表上调用了它而显示出来。]

 public IQueryable<PurchasePendingView> PurchasePendings() {
            var pendings = db.PurchasePendingViews
                             .Where(m => m.AccountStatusID != StructAccountStatus.Succeed); // when I view it in the watch dialougebox I saw all the list items but it shouldn't load at the first place. Is there anything wrong in my approaching or is it just showing because I had call it on the watch. 
            if (ApplicationEnvironment.DEBUGGING) {
                return pendings;
            } else if (IsMobileAccount()) {
                var showroom = db.ShowRooms.FirstOrDefault(m=> m.MemberID == employee.MemberID);
                if (showroom != null) {
                    return pendings.Where(m => m.ShowRoomID == showroom.ShowRoomID);
                } else {
                    return pendings.Where(m => m.CountryDivisionID == employee.CountryDivisionID);
                }
            } else { 
                //normal salary employee can see every detail
                return pendings;
            }
        }

注意:目前我的延迟加载已关闭。

【问题讨论】:

    标签: c# entity-framework linq-to-sql entity-framework-4 linq-to-entities


    【解决方案1】:

    在您第一次遍历结果时评估集合。

    由于您在手表检查器中迭代结果,因此它们会被评估。

    【讨论】:

    • 那么这是否意味着我的查询实际上一开始并没有加载任何内容,最后将它们返回到它将加载的内容?
    • @user1542653 - 否。这意味着您的方法返回 IQueryable 对象,然后结果将在调用者第一次迭代结果时加载。
    • 不,即使你返回它,它也不会加载,直到一些调用代码迭代返回。
    • 是的,明白了。就像我将它转换为 .ToList() 或 ToArray() 或运行 for 循环一样。
    • @user1542653 - 这应该是它自己的问题。
    【解决方案2】:

    这比解释更容易演示:

    public class MeanException : Exception
    {
        public MeanException() : base() { }
        public MeanException(string message) : base(message) { }
    }
    public static IEnumerable<T> Break<T>(this IEnumerable<T> source)
        where T : new()
    {
        if (source != null)
        {
            throw new MeanException("Sequence was evaluated");
        }
        if (source == null)
        {
            throw new MeanException("Sequence was evaluated");
        }
    
        //unreachable
    
        //this will make this an iterator block so that it will have differed execution,
        //just like most other LINQ extension methods
        yield return new T();
    }
    
    public static IEnumerable<int> getQuery()
    {
        var list = new List<int> { 1, 2, 3, 4, 5 };
    
        var query = list.Select(n => n + 1)
            .Break()
            .Where(n => n % 2 == 0);
    
        return query;
    }
    

    那么,我们这里有什么。我们有一个自定义异常,因此我们可以独立捕获它。我们有一个IEnumerable&lt;T&gt; 的扩展方法,它总是会在评估序列时立即抛出异常,但它使用延迟执行,就像SelectWhere 一样。最后,我们有一个获取查询的方法。我们可以在Break 调用之前和之后看到一个LINQ 方法,并且我们可以看到List 被用作底层数据源。 (在您的示例中,它可能是内存中的某个集合,也可能是一个将查询数据库并在迭代时遍历结果的对象。)

    现在让我们使用这个查询看看会发生什么:

    try
    {
        Console.WriteLine("Before fetching query");
        IEnumerable<int> query = getQuery();
        Console.WriteLine("After fetching query");
        foreach (var number in query)
        {
            Console.WriteLine("Inside foreach loop");
        }
        Console.WriteLine("After foreach loop");
    }
    catch (MeanException ex)
    {
        Console.WriteLine("Exception thrown: \n{0}", ex.ToString());
    }
    

    如果您运行此代码,您将看到查询之前的打印(显然)查询之后的打印(这意味着我们只是从方法返回查询并且从未抛出平均异常)以及接下来的消息抛出异常(意味着我们从未进入或超过 foreach 循环的结尾。

    这显然是一个人为的例子来展示一个概念,但这是你在实践中经常看到的东西。例如,如果您在创建数据上下文后失去与数据库的连接,则在迭代查询之前您实际上不会得到异常,或者如果您的数据持有者对象已过期并且不再与数据库匹配' 将在同一点获得异常。在一个不太明显的示例中,如果您长时间保留查询,您将在获取查询结果时得到数据,而不是在构建时得到数据。这是另一个演示:

    var list = new List<int> { 1, 2, 3, 4, 5 };
    
    var query = list.Where(num => num < 5);
    Console.WriteLine(query.Count());
    
    list.RemoveAll(num => num < 4);
    Console.WriteLine(query.Count()
    

    这里我们有一个数据列表,并计算小于 5 的项目数(它是 4)。然后我们修改列表(完全不改变query)。我们重新查询query,最终计数为 1。

    【讨论】:

      猜你喜欢
      • 2011-10-29
      • 2022-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-08
      • 2018-03-13
      • 2014-10-15
      • 1970-01-01
      相关资源
      最近更新 更多