【问题标题】:how to append IQueryable within a loop如何在循环中附加 IQueryable
【发布时间】:2011-11-08 16:17:14
【问题描述】:

我有一个简单的 foreach 循环,它遍历我存储在用户购物篮中的产品 ID,并从数据库中查找产品的详细信息。

从我的代码中可以看出,我目前所拥有的将返回屏幕上的最后一项 - 因为变量在循环中被覆盖。我希望能够将其连接起来,以便仅显示购物篮中商品的产品详细信息。

我知道我可以做一些非常简单的事情,比如在我使用的中继器中只存储 ProductID,然后 onitemdatabound 在那里调用数据库,但如果可能的话,我只想调用一次数据库。

目前我有以下内容(从示例中删除了复杂的连接,但如果这很重要,请告诉我):

IQueryable productsInBasket = null;
    foreach (var thisproduct in store.BasketItems)
    {
        productsInBasket = (from p in db.Products
                                 where p.Active == true && p.ProductID == thisproduct.ProductID
                                 select new
                                 {
                                     p.ProductID,
                                     p.ProductName,
                                     p.BriefDescription,
                                     p.Details,
                                     p.ProductCode,
                                     p.Barcode,
                                     p.Price
                                 });
    }

    BasketItems.DataSource = productsInBasket;
    BasketItems.DataBind();

感谢您的帮助!

【问题讨论】:

    标签: c# entity-framework webforms


    【解决方案1】:

    听起来你真的想要这样的东西:

    var productIds = store.BasketItems.Select(x => x.ProductID).ToList();
    var query = from p in db.Products
                where p.Active && productIds.Contains(p.ProductID)
                select new
                {
                    p.ProductID,
                    p.ProductName,
                    p.BriefDescription,
                    p.Details,
                    p.ProductCode,
                    p.Barcode,
                    p.Price
                };
    

    【讨论】:

    • 嗨,乔恩,谢谢。它奏效了!我以前从来没有想过做这样的过滤器。很容易知道:)
    【解决方案2】:

    在 Jon 的回答中,它工作得很好,但是 IQueryable 将被转换为 IEnumerable,因为您在其上调用 ToList()。这将导致执行查询并检索答案。对于您的情况,这可能没问题,因为您想为一个篮子检索产品,而其中的产品数量可能会相当少。

    然而,我面临着类似的情况,我想为会员检索朋友。友谊取决于两个成员属于哪个组 - 如果他们共享至少一个组,他们就是朋友。因此,我必须检索某个成员的所有组的所有成员资格,然后从这些组中检索所有成员。

    ToList 方法不适用于我的情况,因为每次我想以各种方式处理我的朋友时都会执行查询,例如找到我们可以分享的东西。从数据库中检索所有成员,而不是只处理查询并在可能的最后时间执行它,会降低性能。

    不过,我在这种情况下的第一次尝试就是这样做 - 检索我所属的所有组 (IQueryable),初始化一个列表结果 (IEnumerable),然后遍历所有组并将所有成员附加到结果中(如果它们是)尚未在列表中。最后,由于我的接口强制返回一个 IQueryable,所以我返回了带有 AsIQueryable 的列表。

    这是一段令人讨厌的代码,但至少它有效。它看起来像这样:

    var result = new List<Member>();
    foreach (var group in GetGroupsForMember(member))
        result.AddRange(group.GroupMembers.Where(x => x.MemberId != member.Id && !result.Contains(x.Member)).Select(groupMember => groupMember.Member));
    return result.AsQueryable();
    

    但是,这很糟糕,因为我将所有共享成员添加到列表中,然后将列表转换为 IQueryable 以满足我的发布条件。每次我想对他们做一些事情时,我都会从数据库中检索所有受影响的成员。

    想象一个分页列表——然后我只想从这个列表中挑选出某个范围。如果这是使用 IQueryable 完成的,则查询只是使用分页语句完成。如果这是使用 IEnumerable 完成的,则查询已经执行并且所有操作都应用于内存中的结果。

    (您可能还注意到,我还向下导航实体的关系(GroupMember => 成员),这增加了耦合可能会进一步导致各种令人讨厌的情况。我也想删除这种行为。

    所以,今晚,我又进行了一轮,最终采用了一种更简单的方法,我选择了这样的数据:

    var groups = GetGroupsForMember(member);
    var groupMembers = GetGroupMembersForGroups(groups);
    var memberIds = groupMembers.Select(x => x.MemberId);
    var members = memberService.GetMembers(memberIds);
    

    这两个 Get 方法尊重 IQueryable,并且从不将其转换为列表或任何其他 IEnumerable。第三行只是在 IEnumerable 之上执行 LINQ 查询。最后一行只获取成员 ID 并从另一个服务中检索所有成员,该服务也专门用于 IQueryables。

    这在性能方面可能仍然很糟糕,但如果需要,我可以在以后进一步优化它。至少,我避免加载不必要的数据。

    如果我在这里严重错误,请告诉我。

    【讨论】:

      猜你喜欢
      • 2020-06-10
      • 2018-06-02
      • 1970-01-01
      • 1970-01-01
      • 2019-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-28
      相关资源
      最近更新 更多