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();
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();
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)
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.
Trying to convert the below SQL query to LINQ, but I'm stuck at grouping by ClientCompany.
SELECT TOP 300 ClientCompany,
CASE WHEN MIN(FeatureID) = 12 THEN 1 ELSE 0 END as Sort
FROM Ad
LEFT JOIN AdFeature
ON Ad.ID = AdFeature.AdID
WHERE (AdFeature.FeatureID = 13 OR AdFeature.FeatureID = 12)
AND SiteID = 2
GROUP BY ClientCompany
ORDER BY Sort DESC
My attempt to convert this to LINQ:
(from a in Ads
join af in AdFeatures
on new {
join1 = a.ID,
join3 = 2
} equals new {
join1 = af.AdID,
join3 = af.SiteID
}
let sort = (
af.FeatureID == 12 ? 1 : 0
)
orderby sort descending
where af.FeatureID == 13 || af.FeatureID == 12
select new { a.ClientCompany, sort } ).Take(300)
How would I use MIN(FeatureID) and GROUP BY ClientCompany in LINQ, so that I only get a single row per ClientCompany back?
EDIT
This worked! Based on Daniel Hilgarth's answer. Is there anything that can go horribly wrong with this solution?
Ads.Join(AdFeatures, x => x.ID, x => x.AdID,
(a, af) => new { Ad = a, AdFeature = af })
.Where(x => x.AdFeature.FeatureID == 12 || x.AdFeature.FeatureID == 13)
.Where(x => x.AdFeature.SiteID == 2)
.GroupBy(x => x.Ad.ClientCompany)
.Select(g => new { ClientCompany = g.Key, Sort = g.Min(x => x.AdFeature.FeatureID) == 12 ? 1 : 0 })
.OrderByDescending(x => x.Sort)
.Take(300)
Try this:
Ads.Join(AdFeatures, x => x.FeatureID, x => x.FeatureID,
(a, af) => new { Ad = a, AdFeature = af })
.Where(x => x.AdFeature.FeatureID == 12 || x.AdFeature.FeatureID == 13)
.Where(x => x.AdFeature.SiteID == 2)
.GroupBy(x => x.Ad.ClientCompany)
.Select(g => new { ClientCompany = g.Key,
Sort = g.Min(x => x.AdFeature.FeatureID) == 12 ? 1 : 0 });
Please note, I changed the left outer join into an inner join, because your original query accesses AdFeature unconditionally, making it effectively an inner join .
hi I would write it like that
context.Ads.Where(ad => ad.AdFeatures.Any(feature => (feature.FeatureID == 13 || feature.FeatureID == 12) && feature.SiteID == 2))
.GroupBy(ad => ad.ClientCompany)
.Select(ads => new
{
cc = ads.Key, sort = ads.SelectMany(ad => ad.AdFeatures)
.Select(feature => feature.FeatureID)
.Min() == 12
})
.OrderBy(arg => arg.sort).Take(300);
Try this:
(from a in ads
join af in AdFeatures on a.ID equals af.AdID into g
from x in g.DefaultIfEmpty()
where x.FeatureID == 13 || x.FeatureID == 12
where x.SiteID == 2
orderby a.Sort descending
group a by a.ClientCompany into g2
from x2 in g2
let sort = g2.Select(T => T.FeatureID).Min() == 12 ? 1 : 0
select new { a.ClientCompany, Sort = sort }).Take(300);
Why do you need grouping anyway?