1

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

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

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

 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;
            }
        }

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

4

2 回答 2

6

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

由于您正在遍历手表检查器中的结果,因此将对它们进行评估。

于 2012-10-09T14:26:54.990 回答
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>它总是会在评估序列后立即抛出异常,但它使用延迟执行,就像Selectand一样Where。最后,我们有一个获取查询的方法。我们可以在调用之前和之后看到一个 LINQ 方法Break,并且我们可以看到 aList被用作底层数据源。(在您的示例中,它可能是内存中的某个集合,或者是一个将查询数据库然后在迭代时迭代结果的对象。)

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

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。

于 2012-10-09T15:04:58.233 回答