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)
Related
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();
I have query and I can display values based on condition in SQL. But how can write C# LINQ query is my question.
SELECT Value
FROM db.table
WHERE xxId = 1 AND YYid = 2 AND IsActive = '1' AND IsDeleted = '0'
Result
NNNN
MMMM
TTTT
VVVV
LLLL
I need same query in LINQ C#
var results = db.table
.Select(a => a.xxid == xxid && a.yyid == id &&
a.IsActive && !a.IsDeleted).value;
var results = db.table
.Where(a => a.xxid == xxid && a.yyid == id && a.IsActive && !a.IsDeleted)
.Select(a => a.value)
.ToList();
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)
});
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.
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();