Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
LINQ多列联接_Linq_Join_Left Join_Multiple Columns - Fatal编程技术网

LINQ多列联接

LINQ多列联接,linq,join,left-join,multiple-columns,Linq,Join,Left Join,Multiple Columns,我们的初始查询由许多正确工作的子查询组成,这些子查询基于使用单个列(productId)的联接。生成的模型映射到一个网格,该网格列出了产品名称以及昨天、今天和明天各自所需的数量 然而,收到了一项基于产品年龄的额外差异化要求,因此有必要修改原始查询 因此,下面的代码是对工作代码的修改,它使用单个字段ProductId作为键。在尝试修改查询以使用多列键(ProductId和Age)时,我遇到了问题,收到了以下错误: join子句中某个表达式的类型不正确。调用“GroupJoin”时类型推断失败。 在

我们的初始查询由许多正确工作的子查询组成,这些子查询基于使用单个列(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}和另一个没有名字的名字是一样的

 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进行排序,特别是以下更改似乎产生了所需的结果

  • 在依赖查询中,分组更改为new{p.id,p.ageId}
  • 所有orderby子句都从基于g.Key的单个orderby子句修订为基于g.Key.idg.Key.ageId的两个单独orderby子句
  • 最后,在定义左表的查询中,我使用了以下内容:
  • 新{pr.code,pr.product,pr.uom}新{pr.productId,pr.ageId}分组为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
            });
    
    [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.权重)