LINQ多列联接
我们的初始查询由许多正确工作的子查询组成,这些子查询基于使用单个列(productId)的联接。生成的模型映射到一个网格,该网格列出了产品名称以及昨天、今天和明天各自所需的数量 然而,收到了一项基于产品年龄的额外差异化要求,因此有必要修改原始查询 因此,下面的代码是对工作代码的修改,它使用单个字段ProductId作为键。在尝试修改查询以使用多列键(ProductId和Age)时,我遇到了问题,收到了以下错误: join子句中某个表达式的类型不正确。调用“GroupJoin”时类型推断失败。 在前面创建不同聚合的查询中,我将键更改为ProductId和age的composite,并将一个匿名类型的新成员,productKey分配给一个new{pr.ProductId,pr.age}。然后在最后一个查询中,我试图在productKey equals new{y.productId,y.age}(y表示联接结果“昨天”)上联接这个结果 当我将鼠标悬停在关联结果的每个键(gr.productKey和y.productKey)上时,将为每个键显示以下内容: 'b'a.productKey 匿名类型: 'a是新的{'b productKey,int productId,string age,…} 'b是新的{int productId,string age} 由于这两种类型都是'banew{int productId,string age}我期待成功;然而,编译器仍然不合作。我相信一个新的{int,string}和另一个没有名字的名字是一样的LINQ多列联接,linq,join,left-join,multiple-columns,Linq,Join,Left Join,Multiple Columns,我们的初始查询由许多正确工作的子查询组成,这些子查询基于使用单个列(productId)的联接。生成的模型映射到一个网格,该网格列出了产品名称以及昨天、今天和明天各自所需的数量 然而,收到了一项基于产品年龄的额外差异化要求,因此有必要修改原始查询 因此,下面的代码是对工作代码的修改,它使用单个字段ProductId作为键。在尝试修改查询以使用多列键(ProductId和Age)时,我遇到了问题,收到了以下错误: join子句中某个表达式的类型不正确。调用“GroupJoin”时类型推断失败。 在
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
在昨天的新{gr.productId,gr.age}中加入y,等于y.productKey到outer0
同样,此修改基于的原始查询也可以成功运行。我很确定这是一个“一点知识,是一件危险的事情”的问题。或者可能只是“知之甚少”的问题。不管是哪种方式,我都希望LINQ诸神能找到解决方案。尝试为多列键声明命名类型,而不是使用匿名:
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进行排序,特别是以下更改似乎产生了所需的结果
[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
});
[GridAction]
公共行动结果AjaxOps_行动列表(){
var orders=salesOrderHeaderRepository.All.ToArray();
var details=salesOrderDetailRepository.All.ToArray();
var ages=ageRepository.All.ToArray();
var custAges=customerAgeRepository.All.ToArray();
var types=foodKindRepository.All.ToArray();
var types=foodTypeRepository.All.ToArray();
var units=unitOfMeasureRepository.All.ToArray();
var products=来自productRepository.All.ToArray()中的p
选择新的{
productId=p.productId,
代码=p.名称,
typeId=p.typeId,
kindId=p.kindId,
描述=p.描述,
unitId=p.unitId,
权重=(p==null)?0:p.平均权重
};
var productOrdered=从订单中的o开始
在o.SalesOrderHeaderId等于d.SalesOrderId的详细信息中加入d
在o.CustomerId等于c.CustomerId时加入c
在c.AgeId上加入a。AgeId等于a.AgeId
在d.ProductId等于p.ProductId的乘积中加入p
选择新的{
id=d.ProductId,
代码=p.code,
ageId=a.ageId,
数量=(空==d)?0:d.数量,
权重=((空==d)?0:d.数量)*((空==p)?0:p.权重)