EntityFramework:IQueryable或IEnumerable会在第一时间获得所有结果吗?

时间:2012-10-09 14:25:28

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

我了解到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;
            }
        }

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

2 个答案:

答案 0 :(得分:5)

首次迭代结果时会对集合进行评估。

由于您在监视检查器中迭代结果,因此它们会被逐渐消除。

答案 1 :(得分:0)

这比解释更容易证明:

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<T>的扩展方法,一旦评估序列,它将始终抛出异常,但它使用延迟执行,就像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。