开发LINQ查询,其中列值可以硬编码,但行标题是动态的

如何解决开发LINQ查询,其中列值可以硬编码,但行标题是动态的

在我公司中,我们共有41种产品(U盆,T座,W盆,小便池,白色W盆,粉红色W盆...),但分销商的数量每月都在变化。

我们必须开发一个报告,其中必须显示每个分销商分配的产品数量。 因此,格式将是“产品名称”将构成列标题,而“分销商”名称将成为行标题。 我们已经知道产品名称,因此我们可以在代码中进行硬编码。但是分发服务器的名称正在更改,因此我们无法对其进行硬编码。

下面是模型类和样本数据集。

public class DistributionScale
    {
        public int DistributionScaleId { get; set; }
        [Required]
        public decimal Quantity { get; set; }       
        
        [ForeignKey("ProductId")]
        public Product Products { get; set; } 
        public int ProductId { get; set; }

        [ForeignKey("DistributorsId")]
        public Distributors Distributors { get; set; }
        public int DistributorsId { get; set; }
    }
    
public class Product 
    {
        public int ProductId { get; set; }        
        public string ProductName { get; set; }        
    }
    
 public class Distributors
    {
        public int DistributorsId { get; set; }
        public string DistributorsName { get; set; }                 
    }
    
I have provided some sample data:
List<Distributors> Distributors = new List<Distributors>(){
    new Distributors{DistributorsId = 1,DistributorsName = "S S SUPPLIERS"},new Distributors{DistributorsId = 2,DistributorsName = "HIND SUPPLIERS"},new Distributors{DistributorsId = 3,DistributorsName = "NEXT SUPPLIERS"}
};
List<Product> Product = new List<Product>{
    new Product{ ProductId = 1,ProductName = "U basins" },new Product{ ProductId = 2,ProductName = "Urinals" },new Product{ ProductId = 3,ProductName = "White W basins"}
};
List<DistributionScale> DistributionScale = new List<DistributionScale>(){
    new DistributionScale{DistributionScaleId = 1,Quantity = 1000,ProductId =1,DistributorsId =1    },new DistributionScale{DistributionScaleId = 2,Quantity = 1500,ProductId =2,DistributorsId =  2 },new DistributionScale{DistributionScaleId = 3,Quantity = 2500,ProductId =3,DistributorsId =  3 }
    new DistributionScale{DistributionScaleId = 4,Quantity = 1200,DistributorsId =  3 },new DistributionScale{DistributionScaleId = 5,Quantity = 1300,DistributorsId =  1 }
};

下面是我想做的简单查询。我不以产品名称作为列标题,也不显示图像中所附的分布数据。

public JsonResult ReportDistributionScale()
        {
                var res = (from n in db.DistributionScale
                           join s in db.Product on n.ProductId equals s.ProductId
                           join k in db.Distributors on n.DistributorsId equals k.DistributorsId
                           orderby n.ProductId
                           select new DistributionScaleViewModel
                           {
                                ProductName = s.ProductName,DistributorsName = k.DistributorsName,Quantity = n.Quantity
                           }).ToList();

                return Json(res,JsonRequestBehavior.AllowGet);           
        } 
 
//// another way I am trying 

var res = from n in db.DistributionScale
join s in db.Product on n.ProductId equals s.ProductId
join k in db.Distributors on n.DistributorsId equals k.DistributorsId
  group new
  {
        s.ProductName,k.DistributorsName,n.Quantity
  } by ProductName into g
  select new {
    ///// how to proceed further    
  }).ToList();

已附加图像。我该如何写LINQ以获得如图所示的最终输出。

enter image description here

解决方法

因此,您在产品和DistributionScales之间具有一对多的关系:每个产品都有零个或多个DistributionScale;每个DistributionScale都完全属于一个产品,即外键ProductId所引用的产品。

类似地,您在Distributors和DistributionScales之间也存在一对多的关系:每个Distributor都有零个或多个DistributionScales,每个DistributionScale恰好属于一个Distributor,即外键DistributorId所引用的Distributor。

实际上,这使关系Products-DistributionScales与具有附加值的联结表的多对多关系:数量。

通常在这种情况下,DistributionScales中[ProductId,DistributorId]的组合将是唯一的。您不需要DistributorScales中的以下内容:

  • [id:1,ProductId 10(=小便池),DistributorId 20(=下一个供应商),数量30]
  • [id:2,产品编号10(=小便池),分销商编号20(=下一个供应商),数量40]

下一个供应商有几个小便池? 30吗40吗70?

并且如果下一供应商不再提供小便池,您将如何解决该问题?删除这两个之后,您仍然必须检查整个表以查看是否没有第三种组合[10,20]

如果将组合[ProductId,DistributorId]作为主键,则不会出现此问题,并且不能有多个[ProductId,DistributorId]。提取/更新/删除将更快。

返回您的问题

对于每个分销商,请给我该分销商分发的所有产品的数量,并为该分销商未分发的所有产品提供零数量。

从DistributionScales开始是没有用的,如果这样做的话,您将永远不会获得根本没有分发的产品,也永远不会得到没有分发任何东西的分发者。

您需要从产品方面开始,或者从分销商方面开始:给我所有的分销商,每个分销商都包含他们要分发的产品和他们不分发的产品。

var distributorsAndTheirProducts = dbContext.Distributors.Select(distributor => new
{
   Name = distributor.Name,DistributedProducts = dbContext.DistributionScales
       .Where(distributionScale => distributionScale.DistributorId == distributor.Id)
       .Select(distributionScale => new
       {
           ProductName = dbContext.Products
               .Where(product => product.Id == distributionScale.ProductId)
               .Select(product => product.Name)
               .FirstOrDefault(),Quantity = distributionScale.Quantity,},NonDistributedProducts = ... // TODO

您知道将有一个与此ProductId完全相同的产品,因此如果您愿意,可以使用Single而不是FirstOrDefault。一些实体框架系统不接受此要求,而是需要SingleOrDefault或FirstOrDefault。

如果您认为您可能有几种[尿路,下一个供应商]组合,则必须对数量求和。

现在要获取所有尚未由该分发服务器分发的产品,甚至包括那些没有人分发且因此不在DistributionScales表中的产品,则从“产品”一侧开始。

在“产品”表中,仅保留那些没有此产品的DistributionScale和DistributorId的产品。从剩余的产品中获得名称和数量为零:

    NonDistributedProducts = dbContext.Products
    .Where(product => !dbContect.DistributionScale
        .Where(distributionScale => distributionScale.ProductId == product.Id
                                 && distributionScale.DistributorId == distributor.Id)
        .Any())

它说:如果不存在任何结合了[ProductId,DistributorId]的DistributionScale

   .Select(product => new
   {
       ProductName = product.Name,Quantity = 0,})

因此,您现在每个分销商都有,甚至不分发任何东西的分销商:

  • 姓名
  • DistributedProducts:产品名称/数量组合的顺序
  • NonDistributedProducts:ProductName / 0个组合的序列

很容易看到,如果您将DistributedProducts和NonDistributedProducts结合起来,则每个Distributor都会获得其数量的所有产品,而该Distributor无法分发的产品的数量为零。

把所有东西放在一起,牵着马,因为这将是一个很大的LINQ:

var distributorsAndTheirProducts = dbContext.Distributors.Select(distributor => new
{
   Name = distributor.Name,Products = dbContext.DistributionScales
       .Where(distributionScale => distributionScale.DistributorId == distributor.Id)
       .Select(distributionScale => new
       {
           ProductName = dbContext.Products
               .Where(product => product.Id == distributionScale.ProductId)
               .Select(product => product.Name)
               .FirstOrDefault(),})

       // UNION with the nonDistributedProducts
       Union(dbContext.Products
           .Where(product => !dbContect.DistributionScale
               .Where(distributionScale => 
                   distributionScale.ProductId == product.Id
                && distributionScale.DistributorId == distributor.Id)
           .Any())
           .Select(product => new
           {
               ProductName = product.Name,}))
           .ToList(),});
     

因此,您现在每个分销商都有:它的名称,所有产品,他分销的产品和他不分销的产品。对于所有这些产品:名称和数量;如果该分销商未分发产品,则为零。甚至对于不分发任何东西的分发者,以及没有人分发的产品。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-