如何在循环内附加 IQueryable
我有一个简单的 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();
感谢您的帮助!
I have a simple foreach loop that goes through the productID's I have stored in a user's basket and looks up the product's details from the database.
As you can see from my code, what I have at present will return the very last item on screen - as the variable is overwritten within the loop. I'd like to be able to concat this so that I can display the product details for the items only in the basket.
I know I could do something very easy like store only ProductIDs in the repeater I use and onitemdatabound call the database there but I'd like to make just one database call if possible.
Currently I have the following (removed complex joins from example, but if this matters let me know):
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();
Thanks for your help!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
听起来您真的想要这样的东西:
It sounds like you really want something like:
在 Jon 的回答中,效果很好,但是 IQueryable 将被转换为 IEnumerable,因为您在其上调用了 ToList() 。这将导致执行查询并检索答案。对于您的情况,这可能没问题,因为您想要检索购物篮中的产品,并且产品数量可能相当少。
然而,我面临着类似的情况,我想为会员检索朋友。友谊取决于两个成员属于哪个组 - 如果他们至少共享一个组,那么他们就是朋友。因此,我必须检索某个成员的所有组的所有成员资格,然后检索这些组中的所有成员。
ToList 方法不适用于我的情况,因为每次我想以各种方式处理我的朋友时(例如查找我们可以共享的内容),都会执行查询。从数据库中检索所有成员,而不是仅仅处理查询并在最后可能的时间执行它,将会降低性能。
尽管如此,我在这种情况下的第一次尝试就是这样做 - 检索我所属的所有组(IQueryable),初始化列表结果(IEnumerable),然后循环所有组并将所有成员附加到结果中(如果它们尚未存在)名单。最后,由于我的接口强制返回 IQueryable,所以我使用 AsIQueryable 返回了列表。
这是一段令人讨厌的代码,但至少它有效。它看起来像这样:
但是,这很糟糕,因为我将所有共享成员添加到列表中,然后将列表转换为 IQueryable 只是为了满足我的后置条件。每次我想对他们做一些事情时,我都会检索数据库中受影响的所有成员。
想象一个分页列表 - 然后我只想从此列表中挑选出某个范围。如果使用 IQueryable 完成此操作,则只需使用分页语句即可完成查询。如果这是使用 IEnumerable 完成的,则查询已经执行,并且所有操作都将应用于内存中的结果。
(您可能还注意到,我还向下导航实体的关系(GroupMember => Member),这会增加耦合,从而进一步导致各种令人讨厌的情况。我也想删除这种行为)。
因此,今晚,我又进行了一轮,最终采用了一种更简单的方法,我选择如下数据:
两个 Get 方法遵循 IQueryable,并且从不将其转换为列表或任何其他 IEnumerable。第三行仅在 IEnumerable 之上执行 LINQ 查询。最后一行仅获取成员 ID 并从另一个服务检索所有成员,该服务也专门与 IQueryables 一起使用。
就性能而言,这可能仍然很糟糕,但如果需要的话,我可以稍后进一步优化它。至少,我避免加载不必要的数据。
如果我在这里犯了严重错误,请告诉我。
In Jon's answer, which works just fine, the IQueryable will however be converted to an IEnumerable, since you call ToList() on it. This will cause the query to be executed and the answer retrieved. For your situation, this may be OK, since you want to retrieve products for a basket, and where the number of products will probably be considerably small.
I am, however, facing a similar situation, where I want to retrieve friends for a member. Friendship depends on which group two members belongs to - if they share at least one group, they are friends. I thus have to retrieve all membership for all groups for a certain member, then retrieve all members from those groups.
The ToList-approach will not be applicable in my case, since that would execute the query each time I want to handle my friends in various ways, e.g. find stuff that we can share. Retrieving all members from the database, instead of just working on the query and execute it at the last possible time, will kill performance.
Still, my first attempt at this situation was to do just this - retrieve all groups I belonged to (IQueryable), init an List result (IEnumerable), then loop over all groups and append all members to the result if they were not already in the list. Finally, since my interface enforced that an IQueryable was to be returned, I returned the list with AsIQueryable.
This was a nasty piece of code, but at least it worked. It looked something like this:
However, this is BAD, since I add ALL shared members to a list, then convert the list to an IQueryable just to satisfy my post condition. I will retrieve all members that are affected from the database, every time I want to do stuff with them.
Imagine a paginated list - I would then just want to pick out a certain range from this list. If this is done with an IQueryable, the query is just completed with a pagination statement. If this is done with an IEnumerable, the query has already been executed and all operations are applied to the in-memory result.
(As you may also notice, I also navigate down the entity's relations (GroupMember => Member), which increases coupling can cause all kinds of nasty situations further on. I wanted to remove this behavior as well).
So, tonight, I took another round and ended up with a much simpler approach, where I select data like this:
The two Get methods honor the IQueryable and never convert it to a list or any other IEnumerable. The third line just performs a LINQ query ontop of the IEnumerable. The last line just takes the member IDs and retrieves all members from another service, which also works exclusively with IQueryables.
This is probably still horrible in terms of performance, but I can optimize it further later on, if needed. At least, I avoid loading unnecessary data.
Let me know if I am terribly wrong here.