如何解决开发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以获得如图所示的最终输出。
解决方法
因此,您在产品和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 举报,一经查实,本站将立刻删除。