Sum multiple column in LINQ - c#

How can I reproduce this query using linq?
SELECT
SUM(SecondsSinceLastEvent) as AccessTime,
SUM (case when DownloadType = 0 then 1 end) FileDownloadCount,
SUM (case when DownloadType = 1 then 1 end) KortextDownloadCount,
SUM (case when Action = 'print' then 1 end) PrintCountFROM EReaderLogs WHERE PublishedContent_Id = XXX

In LINQ to Entities you need to first use GroupBy before using multiple aggregate functions. To sum all the elements in a column you can group by some static key so then a single group would be a whole table:
var query = context.EReaderLogs
.Where(e => e.PublishedContent_Id == someValue)
.GroupBy(a => 1, (k, g) =>
{
AccessTime = g.Sum(e => e.SecondsSinceLastEvent),
FileDownloadCount = g.Sum(e => e.DownloadType == 0 ? 1 : 0),
KortextDownloadCount = g.Sum(e => e.DownloadType == 1 ? 1 : 0),
PrintCount = g.Sum(e => e.Action == "print" ? 1 : 0)
});

Related

Convert SUM / CASE WHEN / GROUP BY SQL query into LINQ in C#

I have a table that has some value. I want to group by date month, My date field name is ApplicatonDate, and some enum values.
Here is a SQL query which I need to convert it into Linq:
SELECT
Count(he.ApplicationDate) AS Total,
MAX(he.ApplicationDate) AS ApplicationDate,
SUM(CASE WHEN he.Status=0 then 1 else 0 end )AS Last12MonthTotalPending,
SUM(CASE WHEN he.Status = 1 THEN 1 ELSE 0 END )AS Last12MonthTotalApproved,
SUM(CASE WHEN he.Status = 2 THEN 1 ELSE 0 END )AS Last12MonthTotalDenied
FROM dbo.Client_Heatings he
WHERE he.ApplicationDate >= DATEADD(Year,-1,GETDATE()) AND he.ApplicationDate <= GETDATE()
GROUP BY CAST(ApplicationDate AS DATE)
This is my LINQ. That is my WRONG LINQ.
var result = heatingList
.Where(r => r.Id == 123)
.GroupBy(r =>r.ApplicationDate )
.Select(grp => new HeatingApplicationSummaryDTO
{
Last12MonthTotalPending = grp.Sum( t => t.Status == 0 ? 1 : 0),
Last12MonthTotalApproved = grp.Sum( t => t.Status == 1 ? 1 : 0),
Last12MonthTotalDenied = grp.Sum( t => t.Status == 2 ? 1 : 0),
Total = grp.Sum(c => c.Status)
}).ToList();
I can't convert SQL query to LINQ query. I do not know how to convert and implement SUM/CASE section with Linq.
Thanks in advance
Try the following query:
var endDate = DateTime.Now;
var startDate = endDate.AddYears(-1);
var result = heatingList
.Where(r => r.ApplicationDate >= startDate && r.ApplicationDate <= endtDate)
.GroupBy(r => r.ApplicationDate.Date)
.Select(grp => new HeatingApplicationSummaryDTO
{
Total = grp.Count(),
ApplicationDate = grp.Max(t => t.ApplicationDate),
Last12MonthTotalPending = grp.Sum(t => t.Status == 0 ? 1 : 0),
Last12MonthTotalApproved = grp.Sum(t => t.Status == 1 ? 1 : 0),
Last12MonthTotalDenied = grp.Sum(t => t.Status == 2 ? 1 : 0),
}).ToList();

How to get dictinct userid with order by close using Linq

I have table called info, and its data something like this:
FKUserID
CompletedTime
Type
1
2021-03-10 12:56:00.423
5
245
2021-03-10 12:46:46.977
5
1
2021-03-10 12:44:53.683
5
1
2021-03-10 12:40:54.733
5
1
2021-03-10 12:35:26.307
5
245
2021-03-10 11:11:33.887
5
245
2021-03-10 10:18:11.403
5
I need to get distinct userID data, and also with the maximum completed time of theirs CompletedTime column
expected output is:
FKUserID
CompletedTime
Type
1
2021-03-10 12:56:00.423
5
245
2021-03-10 12:46:46.977
5
I need to do this using Linq query
How can I do this, I did it using SQl, need it using Linq
SELECT FKUserID , MAX(CompletedTime)
from Info
where cast(CompletedTime as date) = '2021-03-10'
and Status = 5
GROUP BY FKUserID;
You can use the following query. The following query implements your SQL query.
var query = context.Info.GroupBy(a => a.FKUserID)
.Join(context.Info,
left => left.Key,
right => right.FKUserID,
(left, right) => new { left, right })
.Where(a => a.right.CompletedTime.ToShortDateString() == "2021-03-10" && a.right.Status == 5)
.Select(a => new
{
FKUserID = a.left.Key,
CompletedTime = a.left.Max(x => x.CompletedTime)
}).ToList();
Something like this
var d = new DateTime(2021, 3, 10);
var d2 = d.AddDays(1);
dbContext.Infos
.Where(i => i.Status == 5 && i.CompletedTime >= d && i.CompletedTime < d2)
.GroupBy(i => i.FkUserId)
.Select(g => new {
FkUserId = g.Key,
CompletedTime = g.Max(g2 => g2.CompletedTime)
}
);

Entity Framework grouped query translated into multiple SELECTs

Can someone help and tell me why this LINQ query is being translated in EF to multiple SELECTs ?
var query = db.ReportedFulfillments.GroupBy(x => x.ContractId).Select(grouping => new
{
ContractId = grouping.Key,
Total = grouping.Count(),
FU = grouping.Count(x => x.Month == 1 && x.Value == 1),
BR = grouping.Count(x => x.Month == 1 && x.Value == 2)
}
I thought that EF will output something like this:
SELECT ContractId,
Count(*) AS Total,
COUNT(CASE WHEN [Month] = 1 AND [Value] = 1 THEN Value END) AS FU,
COUNT(CASE WHEN [Month] = 1 AND [Value] = 2 THEN Value END) AS BR,
FROM ReportedFulfillments GROUP BY ContractId
I'm using EntityFramework 6.2.0
Shortly, LINQ conditional Count of the GroupBy grouping result set is not supported very well (the SQL you expect relies on SQL COUNT(expr) which excludes NULLs and has no LINQ equivalent).
But the equivalent conditional Sum is supported and translated just well, so instead of
FU = grouping.Count(x => x.Month == 1 && x.Value == 1),
BR = grouping.Count(x => x.Month == 1 && x.Value == 2)
use
FU = grouping.Sum(x => x.Month == 1 && x.Value == 1 ? 1 : 0),
BR = grouping.Sum(x => x.Month == 1 && x.Value == 2 ? 1 : 0)

Comparing SQL Date Time in Entity Framework by date parts

I have this query that was actually a view but I wanted to control the WHERE clause so I decided to tackle it by LINQ and EF6:
SELECT NULLIF(SUM([a].[REQUESTED_QTY]), 0) AS [Transaction],
NULLIF(SUM([a].[ITEM_TOTAL]), 0) AS [Income]
FROM [dbo].[BILL_INFO_DETAIL] AS [a]
INNER JOIN [dbo].[SERVICE_INFO] AS [b]
ON [a].[SERVICE_CODE] = [b].[SERVICE_CODE]
WHERE ([a].[INPUT_STATUS] = '1')
AND ([b].[SERVICE_CODE] IN ( 1610, 1611, 1612 ))
AND ([a].[PAY_MODE_ID] IN ( 1, 2 ))
AND (CONVERT(VARCHAR(2), a.STAMP_DATE, 101) IN ( '10', '11', '12' ))
AND (CONVERT(VARCHAR(4), a.STAMP_DATE, 102) IN ( '2017' ))
AND ([b].[FEE] > 1)
After a while of trial and error, I got this conversion:
public async Task<ViewGuessOnline> GetGuessOnline(int[] serviceCodes, byte[] payModes, string[] months, string year)
{
try
{
using (var context = new FinanceConnection())
{
var resultTemp = from a in
(from a in context.BILL_INFO_DETAILS
where
a.INPUT_STATUS == true &&
serviceCodes.Contains(a.SERVICE_INFO.SERVICE_CODE) &&
payModes.Contains(a.PAY_MODE_ID) &&
months.Contains(SqlFunctions.StringConvert(a.STAMP_DATE)) &&
(new[] {"2017"}).Contains(SqlFunctions.StringConvert(a.STAMP_DATE)) &&
a.SERVICE_INFO.FEE > 1
select new
{
a.REQUESTED_QTY,
a.ITEM_TOTAL,
Dummy = "x"
})
group a by new {a.Dummy}
into g
select new
{
Transaction = g.Sum(p => p.REQUESTED_QTY) == 0 ? (int?) null : (int) g.Sum(p => p.REQUESTED_QTY),
Income = g.Sum(p => p.ITEM_TOTAL) == 0 ? (decimal?) null : (decimal) g.Sum(p => p.ITEM_TOTAL)
};
// result = (await result.OrderByDescending(o => o.CustomerCode).ToListAsync()).AsQueryable();
}
Logger.Info($"{LayerName} -> {callerInfo.MethodName} -> Returning");
return result;
}
catch (Exception exp)
{
Logger.Error($"{LayerName} -> {callerInfo.MethodName} -> Exception [{exp.Message}]", exp);
throw;
}
}
I'm having an issue with the date part. In original SQL, the comparison of a Quarter 4 of 2107 is very easy. But I cannot find a proper inline linq conversion that translates to proper SQL.
Also, I had to use a dummy grouping even thoug there is not groups in the original SQL.
A bit more wall-baning and I was able to make this work:
from a in
(from a in db.BILL_INFO_DETAIL
where
a.INPUT_STATUS == true &&
(new int[] {1610, 1611, 1612 }).Contains(a.SERVICE_INFO.SERVICE_CODE) &&
(new int[] {1, 2 }).Contains(a.PAY_MODE_ID) &&
a.STAMP_DATE != null &&
(new int[] {10, 11, 12 }).Contains(a.STAMP_DATE.Value.Month) &&
a.STAMP_DATE.Value.Year == 2017 &&
a.SERVICE_INFO.FEE > 1
select new
{
a.REQUESTED_QTY,
a.ITEM_TOTAL,
Dummy = "x"
})
group a by new {a.Dummy}
into g
select new
{
Transaction = g.Sum(p => p.REQUESTED_QTY) == 0 ? (int?) null : (int) g.Sum(p => p.REQUESTED_QTY),
Income = g.Sum(p => p.ITEM_TOTAL) == 0 ? (decimal?) null : (decimal) g.Sum(p => p.ITEM_TOTAL)
}
I changed the method's parameter datatypes accordingly and this works now.

Converting Sql to Linq using group get wrong result

I have a query where I need to get the count of Commpliance and NonCompliance
Here is the SQL version I need this to convert to linq...
select ScheduleClause,
COUNT(case Compliance
when 1 then 1 end) Compliance,
Count(case Compliance
when 0 then 1 end) NonCompliance
from Compliance_RiskRegisterEntry cr
where cr.RiskRegisterTypeId = 1 and Auditor = 5508 and MONTH(AuditDate) = 10 and YEAR(AuditDate) = 2013
group by ScheduleClause
I try this linq query but I get different result
compliance
.GroupBy(x => new
{
x.ScheduleClause, x.Compliance
})
.Where(x => x.Key.Compliance == 1)
.Select(x => new RiskRegisterCompliancePerCategoryDto
{
ScheduleClause = x.Key.ScheduleClause,
Compliant = x.Key.Compliance == 1 ? 1 : 0,
NonCompliant = x.Key.Compliance == 0 ? 1 : 0,
GrandTotal = x.Count()
}).ToList();
It depends on your exact column definitions. Here I'm using
Create Table Compliance_RiskRegisterEntry (
ScheduleClause varchar(10),
AuditDate datetime not null,
RiskRegisterTypeID int not null,
Auditor Int,
Compliance bit not null
);
With this, the following Linq works:
compliance
.Where(p => p.RiskRegisterTypeID == 1 &&
p.Auditor == 5508 &&
p.AuditDate.Month == 10 &&
p.AuditDate.Year == 2013
)
.GroupBy(x => x.ScheduleClause)
.Select(x => new {
ScheduleClause = x.Key,
Compliant = x.Sum(y => y.Compliance ? 1 : 0),
NonCompliant = x.Sum(y => y.Compliance ? 0 : 1),
GrandTotal = x.Count()
});
Instead of x.Sum(...) you can use x.Count(y.Compliance), but the generated query for this looks much worse than using Sum
compliance
.Where(p=> p.RiskRegisterTypeId = 1 && p.Auditor = 5508 &&
SqlFunctions.DatePart("MM", p.AuditDate) = 10 &&
SqlFunctions.DatePart("yy", p.AuditDate) = 2013)
.GroupBy(x => x.ScheduleClause)
.Select(x => new RiskRegisterCompliancePerCategoryDto
{
ScheduleClause = x.Key.ScheduleClause,
Compliant = x.Key.Compliance == 1 ? 1 : 0,
NonCompliant = x.Key.Compliance == 0 ? 1 : 0,
GrandTotal = x.Count()
}).ToList();

Categories

Resources