[英]C# LINQ statement with joins, group by and having then mapped into list object
I have a model called ElectricityBillSiteExceeding
that looks like this: 我有一个名为
ElectricityBillSiteExceeding
的模型,如下所示:
public class ElectricityBillSiteExceeding
{
public string GroupInvoiceNumber { get; set; }
public int ElectricityBillMainId { get; set; }
public string SiteNo { get; set; }
public decimal BillSiteTotal { get; set; }
public decimal MaximumAmount { get; set; }
}
I want to create a list of this type and use it to feed a grid on one of my pages, the purpose is to show which site has bills that exceed the max amount allowed. 我想创建这种类型的列表,并用它来填充我的页面之一上的网格,目的是显示哪个网站的账单超出了允许的最大数量。
I have written the SQL which will give me this dataset, it looks like this: 我已经编写了SQL,它将给我这个数据集,它看起来像这样:
SELECT SUM(ElectricityBillSiteTotal),
ebs.ElectricityBillMainId,
SiteNo,
ebm.GroupInvoiceNumber,
es.MaximumAmount
FROM dbo.ElectricityBillSites ebs
LEFT JOIN dbo.ElectricityBillMains ebm
ON ebs.ElectricityBillMainId = ebm.ElectricityBillMainId
LEFT JOIN dbo.ElectricitySites es
ON ebs.SiteNo = es.SiteNumber
GROUP BY ebs.ElectricityBillMainId, SiteNo, ebm.GroupInvoiceNumber, es.MaximumAmount
HAVING SUM(ElectricityBillSiteTotal) <> 0 AND SUM(ElectricityBillSiteTotal) > es.MaximumAmount
I'm now in my repository trying to write the method which will go to the database and fetch this dataset so that I can power my grid for the user to see. 我现在在我的存储库中尝试编写该方法,该方法将进入数据库并获取此数据集,以便可以为自己的网格供电,以供用户查看。
This is where I'm struggling. 这就是我努力的地方。 I have written a basic LINQ statement to select from a couple of tables, however I'm unsure how I can incorporate the group by and having clause from my SQL and also how I can then turn this IQueryable object into my
List<ElectricityBillSiteExceeding>
object. 我已经写了一个基本的LINQ语句从几个表中进行选择,但是我不确定如何从SQL中合并group by和having子句,以及如何将IQueryable对象变成
List<ElectricityBillSiteExceeding>
对象。
What I have so far 到目前为止我有什么
public List<ElectricityBillSiteExceeding> GetAllElectricityBillSiteExceedings()
{
var groupedBillSitesThatExceed = from billSites in _context.ElectricityBillSites
join billMains in _context.ElectricityBillMains on billSites.ElectricityBillMainId equals
billMains.ElectricityBillMainId
join sites in _context.ElectricitySites on billSites.SiteNo equals sites.SiteNumber
//TODO: group by total, mainId, siteNo, GroupInv, MaxAmt and Having no total = 0 and total > max
select new
{
groupInv = billMains.GroupInvoiceNumber,
mainId = billMains.ElectricityBillMainId,
siteNo = billSites.SiteNo,
total = billSites.ElectricityBillSiteTotal,
max = sites.MaximumAmount
};
//TODO: Map the result set of the linq to my model and return
throw new NotImplementedException();
}
Can anyone point me in the right direction here? 有人可以在这里指出正确的方向吗?
Before getting into grouping , you need to be aware that the default join
in LINQ is always an INNER JOIN
. 进入分组之前,你需要知道的是,默认
join
在LINQ始终是一个INNER JOIN
。 Take a look at the MSDN page How to: Perform Left Outer Joins . 看看MSDN页面如何:执行左外部联接 。 However, in the solution I'm presenting below, I'm using
INNER JOIN
s since you are using fields from the other tables in your grouping and having clauses. 但是,在下面介绍的解决方案中,由于您正在使用分组和具有子句中其他表中的字段,因此我正在使用
INNER JOIN
。
For reference on grouping using LINQ, check out How to: Group Query Results on MSDN . 有关使用LINQ进行分组的参考,请查看如何:在MSDN上对查询结果进行分组 。
A solution specific to your case is going to look something like: 针对您的案例的解决方案如下所示:
public List<ElectricityBillSiteExceeding> GetAllElectricityBillSiteExceedings()
{
var qryGroupedBillSitesThatExceed = from billSites in _context.ElectricityBillSites
join billMains in _context.ElectricityBillMains on billSites.ElectricityBillMainId equals billMains.ElectricityBillMainId
join sites in _context.ElectricitySites on billSites.SiteNo equals sites.SiteNumber
where billSites.ElectricityBillSiteTotal != 0 && billSites.ElectricityBillSiteTotal > sites.MaximumAmount
group new { billMains.GroupInvoiceNumber, billMains.ElectricityBillMainId, billSites.SiteNo, billSites.ElectricityBillSiteTotal, sites.MaximumAmount }
by new { billMains.GroupInvoiceNumber, billMains.ElectricityBillMainId, billSites.SiteNo, billSites.ElectricityBillSiteTotal, sites.MaximumAmount } into eGroup
select eGroup.Key;
var inMemGroupedBillSitesThatExceed = qryGroupedBillSitesThatExceed.AsEnumerable();
var finalResult = inMemGroupedBillSitesThatExceed.Select(r => new ElectricityBillSiteExceeding()
{
BillSiteTotal = r.ElectricityBillSiteTotal,
ElectricityBillMainId = r.ElectricityBillMainId,
GroupInvoiceNumber = r.GroupInvoiceNumber,
MaximumAmount = r.MaximumAmount,
SiteNo = r.SiteNo,
});
return finalResult.ToList();
}
The correct Linq query for your sql is the following. 下面是您的sql的正确Linq查询。 See Left Join to understand the
DefaultIfEmpty
and also the notes there about the use of ?.
请参阅左联接以了解
DefaultIfEmpty
以及有关使用?.
的注释?.
in the following group by
. 在以下
group by
。
(About the having
- in linq you just provide a where
after the group by
) (关于
having
-在LINQ你只是提供了一个where
后group by
)
var result = from ebs in ElectricityBillSites
join ebm in ElectricityBillMains on ebs.ElectricityBillMainId equals ebm.ElectricityBillMainId into ebmj
from ebm in ebmj.DefaultIfEmpty()
join es in ElectricitySites on ebs.SiteNo equals es.SiteNumber into esj
from es in esj.DefaultIfEmpty()
group new { ebs, ebm, es } by new { ebs.ElectricityBillMainId, ebs.SiteNo, ebm?.GroupInvoiceNumber, es?.MaximumAmount } into grouping
let sum = grouping.Sum(item => item.ebs.ElectricityBillSiteTotal)
where sum > 0 && sum > grouping.Key.MaximumAmount
orderby sum descending
select new ElectricityBillSiteExceeding
{
GroupInvoiceNumber = grouping.Key.GroupInvoiceNumber,
ElectricityBillMainId = grouping.Key.ElectricityBillMainId,
SiteNo = grouping.Key.SiteNo,
BillSiteTotal = sum,
MaximumAmount = grouping.Key.MaximumAmount
};
The error you get: 您得到的错误:
An expression tree lambda may not contain a null propagating operator
表达式树lambda不得包含空传播运算符
By reading this I conclude that you have an older versino of the provider and thus replace the group by code from the code above with the following: 通过阅读此内容,我得出的结论是您拥有提供者的较早版本,因此将上述代码替换为以下代码组:
let GroupInvoiceNumber = ebm == null ? null : ebm.GroupInvoiceNumber
let MaximumAmount = es == null ? 0 : es.MaximumAmount
group new { ebs, ebm, es } by new { ebs.ElectricityBillMainId, ebs.SiteNo, GroupInvoiceNumber, MaximumAmount } into grouping
This probably will be enough. 这可能就足够了。 You could use AutoMapper.
您可以使用AutoMapper。 It will trivialize mapping to classes.
它将简化对类的映射。
var resultList = groupedBillSitesThatExceed
.AsEnumerable() //Query will be completed here and loaded from sql to memory
// From here we could use any of our class or methods
.Select(x => new ElectricityBillSiteExceeding
{
//Map your properties here
})
.ToList(); //Only if you want List instead IEnumerable
return resultList;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.