LINQ query slow - nested Group By and ToList() - linq

I have the following linq query that takes 10 seconds or more to run - is there a better way of writing it? It works, but is just very slow:
var searchQuery = (from p in db.Property
where p.PropertyVendorId == loggedInUserId
from aues in db.ApplicationUserEvents
where aues.ApplicationUserEventsPropertyId == p.PropertyId
&& aues.ApplicationUserEventsFeedbackDate != null
group p by new { p.PropertyId, p.PropertyAddress1, p.PropertyAddress2, p.PropertyAddress3, p.PropertyZipOrPostcode } into pg
select new DashboardFeedback
{
PropertyNumber = pg.FirstOrDefault().PropertyNumber,
PropertyId = pg.FirstOrDefault().PropertyId,
PropertyReference = pg.FirstOrDefault().PropertyId,
PropertyAddress1 = pg.FirstOrDefault().PropertyAddress1,
PropertyAddress2 = pg.FirstOrDefault().PropertyAddress2,
PropertyZipOrPostcode = pg.FirstOrDefault().PropertyZipOrPostcode,
DashboardFeedbackChart = (
from aues2 in db.ApplicationUserEvents
where aues2.ApplicationUserEventsPropertyId == pg.FirstOrDefault().PropertyId
&& aues2.ApplicationUserEventsFeedbackDate != null
from fos in db.FeedbackOptions
where fos.FeedbackOptionsApplicationUserEventsId == aues2.ApplicationUserEventsId
from fo in db.FeedbackOption
where fos.FeedbackOptionsFeedbackOptionId == fo.FeedbackOptionId
group fo by new { fo.FeedbackOptionName, aues2.ApplicationUserEventsPropertyId } into g
select new DashboardFeedbackChart
{
FeedbackOptionName = g.FirstOrDefault().FeedbackOptionName,
FeedbackOptionNameCount = g.Count()
}).ToList<DashboardFeedbackChart>()
}).ToList();
One Property has many ApplicationUserEvents
One ApplicationUserEvents has many FeedbackOptions
One FeedbackOptions has one FeedbackOption
Thanks for any advice!

Related

C#: LINQ not returning the same result as SQL

I'm trying to convert the following SQL query to LINQ, but getting different result count with both,
SQL Query:
SELECT T5.CNTR, T5.BenefitCode,T5.ApprovedFlag,
T5.PaymentFrequencyCode, T5.InstalmentAmt, T5.TotalAmt,
T5.CarRego
FROM
dbo.EmployeeBenefit As T5
LEFT JOIN dbo.Payee ON T5.PayeeCntr = dbo.Payee.CNTR
LEFT JOIN dbo.BankDetails ON dbo.Payee.BankCntr = dbo.BankDetails.BankCntr
Left Join dbo.EmployeeCar As T4 on T5.EmployeeCarCntr=T4.Cntr
Inner Join dbo.EmployeeEntity As T1 On T5.EmployeeEntityCntr=T1.EmployeeEntityCntr
Inner Join dbo.EmployerEntity As T2 On T1.EmployerEntityCntr=T2.EmployerEntityCntr
where T5.EmployeeCntr = 117165
AND ((T5.EndDate is Null) OR (T5.EndDate >= GETDATE()))
LINQ:
var result = (from employeeBenefit in context.EmployeeBenefit
from payee in context.Payee.Where(x => x.Cntr == employeeBenefit.PayeeCntr).DefaultIfEmpty()
from bankDetails in context.BankDetails.Where(x => x.BankCntr == employeeBenefit.PayeeCntr).DefaultIfEmpty()
from employeeCar in context.EmployeeCar.Where(x => x.Cntr == payee.BankCntr).DefaultIfEmpty()
from employeeEntity in context.EmployeeEntity
where employeeEntity.EmployeeEntityCntr == employeeBenefit.EmployeeEntityCntr
from employeeEntity1 in context.EmployeeEntity
where employeeEntity.EmployerEntityCntr == employeeEntity1.EmployerEntityCntr
&& employeeBenefit.EmployeeCntr == iEmployeeID
&& (!employeeBenefit.EndDate.HasValue || employeeBenefit.EndDate >= DateTime.Now)
&& employeeBenefit.EmployeeCntr == 117165
&& employeeBenefit.CarRego == registration
select new
{
CNTR = employeeBenefit.Cntr,
BenefitCode = employeeBenefit.BenefitCode,
PaymentFrequencyCode = employeeBenefit.PaymentFrequencyCode,
InstalmentAmount = employeeBenefit.InstalmentAmt,
TotalAmount = employeeBenefit.TotalAmt,
CarRego = employeeBenefit.CarRego,
ApprovedFlag = employeeBenefit.ApprovedFlag
}).ToList();
Please let me know what i'm missing.
For the data in my database the SQL query is returning 10 records. But, the LINQ is returning 2700 records.
Not a full answer (I'm late for work) but:
var result = (from T5 in context.EmployeeBenefit
join PY in dbo.Payee on T5.PayeeCntr equals PY.CNTR into PY1
where T5.EmployeeCntr = 117165
select new {
CNTR = T5.Cntr,
...
}
).ToList();
It was the issue with the condition mismatch that i had done in the LINQ. The below query just worked fine. Thank you for helping me with the issue.
var result = (from employeeBenefit in context.EmployeeBenefit
from payee in context.Payee.Where(x => x.Cntr == employeeBenefit.PayeeCntr).DefaultIfEmpty()
from bankDetails in context.BankDetails.Where(x => x.BankCntr == payee.BankCntr).DefaultIfEmpty()
from employeeCar in context.EmployeeCar.Where(x => x.Cntr == employeeBenefit.EmployeeCarCntr).DefaultIfEmpty()
join employeeEntity in context.EmployeeEntity
on employeeBenefit.EmployeeEntityCntr equals employeeEntity.EmployeeEntityCntr
join employerEntity in context.EmployerEntity
on employeeEntity.EmployerEntityCntr equals employerEntity.EmployerEntityCntr
where employeeBenefit.EmployeeCntr == 117165 && (!employeeBenefit.EndDate.HasValue || employeeBenefit.EndDate >= DateTime.Now)
select new
{
CNTR = employeeBenefit.Cntr,
BenefitCode = employeeBenefit.BenefitCode,
PaymentFrequencyCode = employeeBenefit.PaymentFrequencyCode,
InstalmentAmount = employeeBenefit.InstalmentAmt,
TotalAmount = employeeBenefit.TotalAmt,
CarRego = employeeBenefit.CarRego,
ApprovedFlag = employeeBenefit.ApprovedFlag
}).ToList();

convert sql query to linq with complex left join

I am new to Linq joins.
i have a sql query as below. Please help me convert the same to linq.
select c.mem_id,
c.po_start,
c.po_end,
isnull(pp.new_policy_code,c.policy_no)
from claims_data c
left join tob_policy tp on (c.subgroup_id =tp.subgroup_id and c.category_id = tp.category_id
and c.service_from_date Between tp.Start_Date And isnull (tp.End_Date,
cast(GETDATE() as date)))
Left Join Tob_Policy_Period Pp On (Pp.Policy_Id = tp.Policy_Id And
c.service_from_date Between Pp.Start_Date And Pp.End_Date )
where c.cid = 13
and c.g_id = 19013
and c.mem_id = '123'
and c.code ='555'
Try with this code:
var results = (from c in yourmodelentity.claims_data
join tp in yourmodelentity.tob_policy on c.subgroup_id equals tp.subgroup_id && c.category_id equals tp.category_id && c.service_from_date Between tp.Start_Date && isnull (tp.End_Date, datetime.now)))
join Pp in yourmodelentity.Tob_Policy_Period on Pp.Policy_Id equals tp.Policy_Id && c.service_from_date Between Pp.Start_Date && Pp.End_Date
where c.cid = 13 && c.g_id = 19013 && c.mem_id = '123' && c.code ='555'
select new
{
c.mem_id,
c.po_start,
c.po_end
}).ToList();
Try with below code:
var results = (from c in modelentity.claims_data
join tp in modelentity.tob_policy on new { first = c.subgroup_id, second= c.category_id } equals new { first = tp.subgroup_id, second = tp.category_id } into tpjoin
from tplj in tpjoin.DefaultIfEmpty()
join pp in modelentity.Tob_Policy_Period on new { first = tplj.Policy_Id ?? 0 } equals new { first = Pp.Policy_Id } into ppjoin
from pplj in tpjoin.DefaultIfEmpty()
where ((c.service_from_date) >= tplj.Start_Date && (c.service_from_date) <= (tplj.End_Date ?? DateTime.Now)) &&
((c.service_from_date) >= pplj.Start_Date && (c.service_from_date) <= pplj.End_Date) &&
(c.cid = 13 && c.g_id = 19013 && c.mem_id = "123" && c.code = "555")
select new
{
c.mem_id,
c.po_start,
c.po_end,
policy_no = (pplj != null ? (pplj.new_policy_code ?? c.policy_no) : c.policy_no)
}).ToList();

How do I optimize this LINQ query? It runs localhost but it doesn't run on Azure

I have this LINQ query and am getting results I need. However it takes 5-6 seconds to show results on localhost, and I can't even run this on Azure.
I'm new to LINQ, and I'm sure that I'm doing something inefficient.
Could someone direct me to optimize?
var joblist = (from t in db.Tracking
group t by t.JobNumber into j
let id = j.Max(x => x.ScanDate)
select new
{
jn = j.Key,
ti = j.FirstOrDefault(y => y.ScanDate == id).TrackingId,
sd = j.FirstOrDefault(y => y.ScanDate == id).ScanDate,
lc = j.FirstOrDefault(y => y.ScanDate == id).LocationId
}).Where(z => z.lc == lid).Where(z => z.jn != null);
jfilter = (from tr in joblist
join lc in db.Location on tr.lc equals lc.LocationId
join lt in db.LocType on lc.LocationType equals lt.LocationType
select new ScanMod
{
TrackingId = tr.ti,
LocationName = lc.LocationName,
JobNumber = tr.jn,
LocationTypeName = lt.LocationTypeName,
ScanDate = tr.sd,
StoneId = ""
}).OrderByDescending(z => z.ScanDate);
UPDATE:
This query runs on Azure(s1) but it takes 30 seconds. This table has 500,000 rows and I assume that OrderByDescending or FirstOrDefault is killing it...
var joblist = db.Tracking
.GroupBy(j => j.JobNumber)
.Select(g => g.OrderByDescending(j => j.ScanDate).FirstOrDefault());
jfilter = (from tr in joblist
join lc in db.Location on tr.LocationId equals lc.LocationId
join lt in db.LocType on lc.LocationType equals lt.LocationType
where tr.LocationId == lid
select new ScanMod
{
TrackingId = tr.TrackingId,
LocationName = lc.LocationName,
JobNumber = tr.JobNumber,
LocationTypeName = lt.LocationTypeName,
ScanDate = tr.ScanDate,
StoneId = ""
}).OrderByDescending(z => z.ScanDate);

Ignore null and get full result

I have below linq select coding. The result become empty if db.actions.ACTC_DBID values are null. How to avoid that. I need to get the query result with null values.
var apList = (from r in db.components
join o in db.cmp_actionpanel on r.CMP_DBID equals o.CMP_DBID
join u in db.cmp_button on o.BTN_DBID equals u.BTN_DBID
join a in db.actions on o.ACTC_DBID equals a.ACTC_DBID
where (r.ORG_DBID == org && r.CMP_DBID == id)
orderby o.ORDER_IDX
select new
{
AP_DBID = o.AP_DBID,
CMP_NAME = r.CMP_NAME,
CMP_DBID = r.CMP_DBID,
BTN_NAME = u.BTN_NAME,
BTN_DBID = u.BTN_DBID,
ORDER_IDX = o.ORDER_IDX,
ALWAYS_VISIBLE = o.ALWAYS_VISIBLE,
ACTC_DBID = a.ACTC_DBID,
ACTION_CODE = a.ACTION_CODE,
ACTION_CMP_DBID = o.ACTION_CMP_DBID,
STARTS_JOB_PROGRESSION = o.STARTS_JOB_PROGRESSION,
VISIBLE_ON = o.VISIBLE_ON,
CAPTURE_INFO = o.CAPTURE_INFO,
COMMAND = o.COMMAND
}).ToList();
var apList = (from r in db.components
join o in db.cmp_actionpanel on r.CMP_DBID equals o.CMP_DBID
join u in db.cmp_button on o.BTN_DBID equals u.BTN_DBID
join a in db.actions on o.ACTC_DBID equals a.ACTC_DBID into aGroup
where (r.ORG_DBID == org && r.CMP_DBID == id)
orderby o.ORDER_IDX
from ag in aGroup.DefaultIfEmpty()
select new
{
AP_DBID = o.AP_DBID,
CMP_NAME = r.CMP_NAME,
CMP_DBID = r.CMP_DBID,
BTN_NAME = u.BTN_NAME,
BTN_DBID = u.BTN_DBID,
ORDER_IDX = o.ORDER_IDX,
ALWAYS_VISIBLE = o.ALWAYS_VISIBLE,
ACTC_DBID = ag.ACTC_DBID == null ? (int?)null : ag.ACTC_DBID,
ACTION_CODE = ag.ACTION_CODE,
ACTION_CMP_DBID = o.ACTION_CMP_DBID,
STARTS_JOB_PROGRESSION = o.STARTS_JOB_PROGRESSION,
VISIBLE_ON = o.VISIBLE_ON,
CAPTURE_INFO = o.CAPTURE_INFO,
COMMAND = o.COMMAND
}).ToList();

Error trying to exclude records with a JOIN to another object

In my code below, is there any way I can use the results in the object 'WasteRecordsExcluded' to join with searchResults, essentially excluding the WasteId's I don't want.
If I debug to the last line I get the error :
base {System.SystemException} = {"The query contains references to items defined on a different data context."}
Or if joining is impossible then i could change bHazardous from TRUE to FALSE and FALSE to TRUE and do some kind of 'NOT IN' comparison.
Going bananas with this one, anyone help? Kind Regards :
var allWaste = _securityRepository.FindAllWaste(userId, SystemType.W);
var allWasteIndicatorItems = _securityRepository.FindAllWasteIndicatorItems();
// First get all WASTE RECORDS
var searchResults = (from s in allWaste
join x in allWasteIndicatorItems on s.WasteId equals x.WasteId
where (s.Description.Contains(searchText)
&& s.Site.SiteDescription.EndsWith(searchTextSite)
&& (s.CollectedDate >= startDate && s.CollectedDate <= endDate))
&& x.EWC.EndsWith(searchTextEWC)
select s).Distinct();
var results = searchResults;
if (hazardous != "-1")
{
// User has requested to filter on Hazardous or Non Hazardous only rather than Show All
var WasteRecordsExcluded = (from we in _db.WasteIndicatorItems
.Join(_db.WasteIndicators, wii => wii.WasteIndicatorId, wi => wi.WasteIndicatorId, (wii, wi) => new { wasteid = wii.WasteId, wasteindicatorid = wii.WasteIndicatorId, hazardtypeid = wi.HazardTypeId })
.Join(_db.HazardTypes, w => w.hazardtypeid, h => h.HazardTypeId, (w, h) => new { wasteid = w.wasteid, hazardous = h.Hazardous })
.GroupBy(g => new { g.wasteid, g.hazardous })
.Where(g => g.Key.hazardous == bHazardous && g.Count() >= 1)
select we);
// Now join the 2 object to eliminate all the keys that do not apply
results = results.Where(n => WasteRecordsExcluded.All(t2 => n.WasteId == t2.Key.wasteid));
}
return results;
Maybe something like this:
.....
var results = searchResults.ToList();
.....
.....
.Where(g => g.Key.hazardous == bHazardous && g.Count() >= 1)
select we).ToList();
.....

Resources