C# 如何提高我的LINQ
下面的查询确实解决了我的问题,但它似乎过于复杂 问题是我有一个存储菜单选项(id、名称、说明和价格)的表。我还有一个会话变量,它将用户的选择存储在字典中(存储id和数量) 我在下面生成的LINQ基本上计算了所有汇总的值。它将表格转换为字典,然后将价格乘以数量求和 有更好的方法吗C# 如何提高我的LINQ,c#,linq,C#,Linq,下面的查询确实解决了我的问题,但它似乎过于复杂 问题是我有一个存储菜单选项(id、名称、说明和价格)的表。我还有一个会话变量,它将用户的选择存储在字典中(存储id和数量) 我在下面生成的LINQ基本上计算了所有汇总的值。它将表格转换为字典,然后将价格乘以数量求和 有更好的方法吗 var prices = _db.MenuOptions .Select(o => new { o.Id, o.Price }) .ToDiction
var prices = _db.MenuOptions
.Select(o => new { o.Id, o.Price })
.ToDictionary(o => o.Id, o => o.Price);
Session["price"] = prices
.Where(p => orderItems.Keys.Contains((int)p.Key))
.Sum(p => p.Value * orderItems[p.Key]);
我马上想到的一件事是循环使用
orderItems.Keys
,而不是prices
,然后按键过滤它们
假设orderItems是一个标准字典,那么它实现了IEnumerable
。这意味着我们可以做如下事情:
Session["price"] = orderItems.Sum(x=>x.Value*prices[x.Key]);
您可能可以通过执行联接将所有内容合并到一个查询中,但我个人认为,这种方式更具可读性
除了更简洁、可读性更强之外,这样做更好的原因是,当原始方法只需要非常有限数量的元素时,它将遍历所有的price字典。实际上,只有与orderItems匹配的元素。因此,当我们知道我们想要所有的物品时,在较小的清单上订购更有意义
只有当orderItems字典中的某个项目在prices字典中没有相应的条目时,这才有可能失败,但我认为这永远不会发生。如果是这样,您需要进行适当的防护。选择的
部分没有必要,可以删除:
var prices = _db.MenuOptions.ToDictionary(o => o.Id, o => o.Price);
而价格
计算可以从订单项
开始:
Session["price"] = orderItems.Sum(oi => oi.Value * prices[oi.Key]);
(假设所有orderItems
都有db中的价格。)
编辑:从Arcturus answer开始,对于“一行”也可以这样做,但速度可能较慢(见注释):
既然可以直接使用数据,为什么要先创建一个匿名类,并将这些内容放在字典中呢
Session["price"] = _db.MenuOptions
.Where(p => orderItems.Keys.Contains((int)p.Id))
.Sum(p => p.Price * orderItems[p.Id]);
实际上,原始代码并不坏,因为它只加载所需的列,尽管它对所有菜单选项都这样做
更好的解决方案是仅从数据库加载订购项目的价格:
var prices = _db.MenuOptions
.Where(o => orderItems.Keys.Contains(o.Id))
.Select(o => new { o.Id, o.Price })
.ToDictionary(o => o.Id, o => o.Price);
Session["price"] = orderItems.Sum(oi => oi.Value * prices[oi.Key]);
Select
语句确保只加载ID和Price,并且不能删除。
Where
语句将在(..)
子句中创建一个Where ID,只返回订单项目的价格。我觉得还可以,我在这里看到了更多奇特的结构。\u db
是什么?您使用的是类似ORM的实体框架还是NHibernate?\u db使用的是EntityFramework。这个问题似乎与主题无关,因为它是关于改进工作代码,而不是解决实际问题。我想这会很好,我会在以后的评论中发表。我的问题似乎已经在这里得到了回答。谢谢。如果orderItems包含的项目可能比价格多,这可能不起作用。@Arcturus:我刚刚添加了一条关于这一点的注释。从上下文来看,我认为这是不应该发生的(我认为这是一种电子商务类型的情况,订单项是从所有有价格的产品中选择的),但这肯定是值得提高的。非常正确。。奇怪的是,这个示例正在解析菜单项中的价格,而不是使用数据库值。@Arcturus:的确如此。我不想开始怀疑这一点。:)这里的菜单选项可能意味着在餐厅用餐或类似的事情。这可能无法编译,具体取决于\u db
是什么。如果它是像EF这样的ORM,它可能会抱怨它不能将orderItems[p.Id]
转换为SQL对不起,我应该提到它使用的是EntityFramework,因此我首先将数据拉入业务逻辑。比我的要简洁得多,另外还简化了第一部分(我很不好意思错过了那个简单的优化)。一行程序将循环遍历每个订单项的所有选项。它与原始的不一样,性能更差。如果\u db
是ORM,您甚至会执行多个queries@PanagiotisKanavos澄清了这一点。另一个问题是,您正在加载所有选项的所有字段,即使只有已排序的ite的选项ms是必需的。select
部分只需加载价格和IDs@PanagiotisKanavos你是说只有一行吗?我认为LINQ比这更聪明,但可能不是……在这种情况下,prices
和orderItems
应该具有相同的长度,从何处开始定价并不重要因此,为了使原始代码的变化最小,只需移动Where()
方法即可。
var prices = _db.MenuOptions
.Where(o => orderItems.Keys.Contains(o.Id))
.Select(o => new { o.Id, o.Price })
.ToDictionary(o => o.Id, o => o.Price);
Session["price"] = orderItems.Sum(oi => oi.Value * prices[oi.Key]);