我们的初始查询由许多子查询组成,这些子查询基于使用单个列(productId)的连接而正常工作。生成的模型映射到一个网格,该网格列出了产品名称及其昨天,今天和明天各自所需的数量。
但是,根据产品的使用年限收到了额外差异化的要求,因此有必要修改原始查询。
因此,以下代码是对使用单个字段的工作代码的修改,即ProductId作为键。在尝试修改查询以使用多列密钥(ProductId和Age)时遇到了麻烦,收到以下错误:
join子句中某个表达式的类型不正确。调用“GroupJoin”时类型推断失败。
在前面创建Distinct Aggregate的查询中,我将密钥更改为ProductId和age的复合,并将匿名类型的新成员 productKey 分配给 new {pr.productId ,pr.age} 。然后在最后的查询中,我试图加入这个结果 on productKey equals new {y.productId,y.age} (y代表加入结果“昨天”)。
当我将鼠标悬停在已连接结果的每个键(gr.productKey和y.productKey)上时,会为每个键显示以下内容:
'b'a.productKey
匿名类型:
'a is new {'b productKey,int productId,string age,...}
'b是新的{int productId,字符串年龄}
由于两者都是'b 类型 new {int productId,string age} ,我期待成功;但是,编译器继续不合作。我相信一个 new {int,string} 与另一个名字相同。
var yesterday = from p in productOrdered
where p.deliveryDate.Date == DateTime.Now.AddDays(-1).Date
group p by new { p.id, p.age } into g
orderby g.Key
select new {
productKey = g.Key,
productId = g.Max(s => s.id),
age = g.Max(s => s.age),
quantity = g.Count(),
weight = g.Sum(s => s.weight),
};
var grp = (from pr in prods2
group pr by new { pr.productId, pr.age } into g
orderby g.Key
select new {
productKey = g.Key,
productId = g.Max(s => s.productId),
age = g.Max(s => s.age),
code = g.Max(s => s.code),
product = g.Max(s => s.product),
uom = g.Max(s => s.uom)
}).Distinct();
var model = from gr in grp
join y in yesterday on gr.productKey equals new { y.productId, y.age } into outer0
from y in outer0.DefaultIfEmpty()
join n in now on gr.productKey equals new { n.productId, n.age } into outer1
from n in outer1.DefaultIfEmpty()
join t in tomorrow on gr.productKey equals new { t.productId, t.age } into outer2
from t in outer2.DefaultIfEmpty()
select new RequiredProductsViewModel
{
ProductId = gr.productId,
Aged = gr.age,
Code = gr.code.ToString(),
Description = gr.product.ToString(),
MinusQ = (!(null == y) ? y.quantity : 0),
MinusW = (!(null == y) ? decimal.Parse(y.weight.ToString()) : 0),
ZeroQ = (!(null == n) ? n.quantity : 0),
ZeroW = (!(null == n) ? decimal.Parse(n.weight.ToString()) : 0),
OneQ = (!(null == t) ? t.quantity : 0),
OneW = (!(null == t) ? decimal.Parse(t.weight.ToString()) : 0),
UofM = gr.uom.ToString()
};
LINQPad中的测试产生了类似的结果,我还根据本网站上的类似问题尝试了几种变体,例如但不限于以下内容:
昨天加入y 新{Key1 = gr.productId,Key2 = gr.age}等于y.productKey 进入outer0
昨天加入y new {gr.productId,gr.age} 等于y.productKey进入outer0
同样,此修改所依赖的原始查询可以成功运行。我很确定这是“一点点知识,是一件危险的事情”之一。或者只是“小知识”问题。无论哪种方式,我希望LINQ众神可以看到解决方案。
答案 0 :(得分:0)
尝试为多列密钥声明命名类型,而不是使用匿名:
public class ProductKey
{
public int ProductId { get; set; }
public int ProductAge { get; set; }
}
在“group by”和“join”子句中使用此ProductKey。 所以你的查询看起来像:
var yesterday = from p in productOrdered
where p.deliveryDate.Date == DateTime.Now.AddDays(-1).Date
group p by new ProductKey { ProductId=p.id, ProductAge=p.age } into g
orderby g.Key.ProductId
select new {
productKey = g.Key,
productId = g.Max(s => s.id),
age = g.Max(s => s.age),
quantity = g.Count(),
weight = g.Sum(s => s.weight),
};
var grp = (from pr in prods2
group pr by new ProductKey{ ProductId=pr.productId, ProductKey=pr.age } into g
orderby g.Key.ProductId
select new {
productKey = g.Key,
productId = g.Max(s => s.productId),
age = g.Max(s => s.age),
code = g.Max(s => s.code),
product = g.Max(s => s.product),
uom = g.Max(s => s.uom)
}).Distinct();
var model = from gr in grp
join y in yesterday on gr.productKey equals new ProductKey { ProductId=y.productId, ProductAge=y.age } into outer0
from y in outer0.DefaultIfEmpty()
join n in now on gr.productKey equals new ProductKey { ProductId=n.productId, ProductAge=n.age } into outer1
from n in outer1.DefaultIfEmpty()
join t in tomorrow on gr.productKey equals new ProductKey { ProductId=t.productId, ProductAge=t.age } into outer2
from t in outer2.DefaultIfEmpty()
select new RequiredProductsViewModel
{
ProductId = gr.productId,
Aged = gr.age,
Code = gr.code.ToString(),
Description = gr.product.ToString(),
MinusQ = (!(null == y) ? y.quantity : 0),
MinusW = (!(null == y) ? decimal.Parse(y.weight.ToString()) : 0),
ZeroQ = (!(null == n) ? n.quantity : 0),
ZeroW = (!(null == n) ? decimal.Parse(n.weight.ToString()) : 0),
OneQ = (!(null == t) ? t.quantity : 0),
OneW = (!(null == t) ? decimal.Parse(t.weight.ToString()) : 0),
UofM = gr.uom.ToString()
};
<强>更新强>
带有ProductKey类的ORDER BY子句将给出错误(linq不知道如何订购多个列类)所以你应该通过g.Key.ProductId专门订购
答案 1 :(得分:0)
以下更改似乎产生了所需的结果。
将 new {pr.productId,pr.ageId} 新{pr.code,pr.product,pr.uom} 分组到g
之前我曾在另一种方法中成功使用过此变体,但忘记了我遇到过它的地方。它确实精确地定义了字段和复合键。
此方法现在生成订购产品的汇总列表,其中包含其数量和权重的总和。此外,具有不同年龄要求的产品将单独列出。最终,我们得到的产品清单仅显示已订购的产品,按年龄分组,显示数量和重量,过期订单,今天订单和明天订单。
我已将此方法的所有代码都包含在内,以帮助解决某些问题,并为那些具有更高技能的人提供挑战。
[GridAction]
public ActionResult AjaxOps_ActionList() {
var orders = salesOrderHeaderRepository.All.ToArray();
var details = salesOrderDetailRepository.All.ToArray();
var ages = ageRepository.All.ToArray();
var custAges = customerAgeRepository.All.ToArray();
var kinds = foodKindRepository.All.ToArray();
var types = foodTypeRepository.All.ToArray();
var units = unitOfMeasureRepository.All.ToArray();
var products = from p in productRepository.All.ToArray()
select new {
productId = p.ProductId,
code = p.Name,
typeId = p.TypeId,
kindId = p.KindId,
Description = p.Description,
unitId = p.UnitId,
weight = (p == null) ? 0 : p.AverageWeight
};
var productOrdered = from o in orders
join d in details on o.SalesOrderHeaderId equals d.SalesOrderId
join c in custAges on o.CustomerId equals c.CustomerId
join a in ages on c.AgeId equals a.AgeId
join p in products on d.ProductId equals p.productId
select new {
id = d.ProductId,
code = p.code,
ageId = a.AgeId,
quantity = (null == d) ? 0 : d.Quantity,
weight = ((null == d) ? 0 : d.Quantity) * ((null == p) ? 0 : p.weight),
deliveryDate = o.DeliveryDateTime
};
var tomorrow = from p in productOrdered
where p.deliveryDate.Date == DateTime.Now.AddDays(1).Date
group p by new { p.id, p.ageId} into g
orderby g.Key.id
orderby g.Key.ageId
select new {
productId = g.Key.id,
ageId = g.Key.ageId,
quantity = g.Count(),
weight = g.Sum(s => s.weight)
};
var now = from p in productOrdered
where p.deliveryDate.Date == DateTime.Now.Date
group p by new { p.id, p.ageId } into g
orderby g.Key.id
orderby g.Key.ageId
select new {
productId = g.Key.id,
ageId = g.Key.ageId,
quantity = g.Count(),
weight = g.Sum(s => s.weight)
};
var yesterday = from p in productOrdered
where p.deliveryDate.Date == DateTime.Now.AddDays(-1).Date
group p by new { p.id, p.ageId } into g
orderby g.Key.id
orderby g.Key.ageId
select new {
productId = g.Key.id,
ageId = g.Key.ageId,
quantity = g.Count(),
weight = g.Sum(s => s.weight)
};
var prods = from pr in products
join p in productOrdered on pr.productId equals p.id
join t in types on pr.typeId equals t.FoodTypeId
join k in kinds on pr.kindId equals k.FoodKindId
join u in units on pr.unitId equals u.AUnitMeasureId
select new {
productId = pr.productId,
ageId = p.ageId,
code = pr.code,
product = t.Name + " " + k.Name + " " + pr.Description,
uom = u.Name
};
var grp = (from pr in prods
group new { pr.code, pr.product, pr.uom} by new { pr.productId, pr.ageId} into g
orderby g.Key.productId
orderby g.Key.ageId
select new {
productKey = g.Key,
productId = g.Key.productId,
ageId = g.Key.ageId,
code = g.Max(s => s.code),
product = g.Max(s => s.product),
uom = g.Max(s => s.uom)
}).Distinct();
var model = from gr in grp
join y in yesterday on gr.productKey equals new { y.productId, y.ageId } into outer0
from y in outer0.DefaultIfEmpty()
join n in now on gr.productKey equals new { n.productId, n.ageId } into outer1
from n in outer1.DefaultIfEmpty()
join t in tomorrow on gr.productKey equals new { t.productId, t.ageId } into outer2
from t in outer2.DefaultIfEmpty()
select new RequiredProductsViewModel
{
ProductId = gr.productId,
Code = gr.code.ToString(),
Description = gr.product.ToString(),
AgeId = gr.ageId,
MinusQ = (!(null == y) ? y.quantity : 0),
MinusW = (!(null == y) ? decimal.Parse(y.weight.ToString()) : 0),
ZeroQ = (!(null == n) ? n.quantity : 0),
ZeroW = (!(null == n) ? decimal.Parse(n.weight.ToString()) : 0),
OneQ = (!(null == t) ? t.quantity : 0),
OneW = (!(null == t) ? decimal.Parse(t.weight.ToString()) : 0),
UofM = gr.uom.ToString()
};
return View(new GridModel<RequiredProductsViewModel>
{
Data = model
});
最有可能会有其他(也许是更好的)解决方案;然而,这是有效的,这是我的故事,我坚持它。
最后要感谢PanJanek冒着时间提出建议。如果您找到任何改进方法,请告诉我。