Implementing where clause in LINQ with join - c#

I have this LINQ (LINQ TO ENTITY):
var clientFullReview = (from cr in clientReview
join ir in inspectionReviews on cr.siteId equals ir.SiteId into g
from subsite in g.DefaultIfEmpty()
select new
{
clientId = cr.clientId,
clientName = cr.clientName,
siteId = cr.siteId == null ? -1 : cr.siteId,
inspectionReviewId = (subsite == null ? -1 : subsite.Id),
inspectionFrequency = (subsite == null ? -1 : subsite.FrequencyId),
isNormal = (subsite == null ? false : subsite.IsNormal)
});
In the link above I need to use where clause.
inspectionReviews - has date property.
In the LINQ abouve I want to make join only inspectionReviews records that has specific date ,like that:
var clientFullReview = (from cr in clientReview
join ir in inspectionReviews on cr.siteId equals
where ir.DateReview.Year == date.Year &&
ir.DateReview.Month == date.Month
into g
from subsite in g.DefaultIfEmpty()
select new
{
clientId = cr.clientId,
clientName = cr.clientName,
siteId = cr.siteId == null ? -1 : cr.siteId,
inspectionReviewId = (subsite == null ? -1 : subsite.Id),
inspectionFrequency = (subsite == null ? -1 : subsite.FrequencyId),
isNormal = (subsite == null ? false : subsite.IsNormal)
});
But when I try to implement it with where clause I get this error:
A query body must end with a select clause or a group clause
on this key word: into in second LINQ.
So my question how can I filter data by date when I implement join?

One way
join ir in inspectionReviews.Where(x =>
x.DateReview.Year == date.Year && x.DateReview.Month == date.Month)
on cr.siteId equals ir.SiteId
Another way
join ir in (from x in inspectionReviews
where x.DateReview.Year == date.Year && x.DateReview.Month == date.Month
select x)
on cr.siteId equals ir.SiteId
Yet another way
join ir on cr.siteId equals ir.SiteId into g
from subsite in g
.Where(x => x.DateReview.Year == date.Year && x.DateReview.Month == date.Month)
.DefaultIfEmpty()

Join clause allows only equals, so if you need to filter the joined collection, you can use the subsite variable under the second from clause:
join ir in inspectionReviews on cr.siteId equals ir.SiteId
into g
from subsite in g.DefaultIfEmpty()
where subsite.DateReview.Year == date.Year &&
subsite.DateReview.Month == date.Month

Break it intotwo queries and do your second select from the filterest first list.
I am not going to reproduce your code because I think it has some text missing, on the second join value, but the idea is to do it in two steps:
var clientFullReviews = (from cr in clientReview
join ir in inspectionReviews on cr.siteId equals
where ir.DateReview.Year == date.Year &&
ir.DateReview.Month == date.Month
into g
var clientcurrent reviews =(from cr clientFullReviews select new
{
clientId = cr.clientId,
clientName = cr.clientName,
siteId = cr.siteId == null ? -1 : cr.siteId,
inspectionReviewId = (subsite == null ? -1 : subsite.Id),
inspectionFrequency = (subsite == null ? -1 : subsite.FrequencyId),
isNormal = (subsite == null ? false : subsite.IsNormal)
});
This isn't perfect syntax because I don't know your data objects well enough, but you get the idea. I am not sure if you will take a performance hit doing it this way, but I almost always break it up like this to keep my Linq syntax clean and readable (and to keep from confusing myself with too many extension expressions in one line!)

Related

How to filter data using ternary operator in linq

var PFOpeningList = (from emp in dbContext.EmployeeList
join dsg in dbContext.hrmDesig on emp.HrmDesignationId equals dsg.Id into DsgLeftJoin
from dsgleftjoin in DsgLeftJoin.DefaultIfEmpty()
join opb in dbContext.PfOpeningBalances on emp.Id equals opb.HrmEmployeeId into OpbLeftJoin
from opbleftjoin in OpbLeftJoin.DefaultIfEmpty()
where opbleftjoin.CmnCalendarYearId == clndrId
&& (empId != 0 ? emp.Id == empId
: (dptId != 0 ? emp.HrmDepartmentId == dptId
: (officId != 0 ? emp.HrmOfficeId == officId : emp.CmnCompanyId == CmnId)))
&& emp.CmnCompanyId == CmnId
select new
{
EmployeeId=emp.Id,
EmployeeName=emp.Name,
Designation = dsgleftjoin.Name,
OpeningIncome = (decimal?)opbleftjoin.OpeningIncome,
EmployeeContribution = (decimal?)opbleftjoin.EmployeeContribution,
CompanyContribution = (decimal?)opbleftjoin.CompanyContribution
}).ToList();
I want to achieve all employees with designation(hrmDesig) from EmployeeList. Filtering with Calendar Year is mandatory. But if user select Office/Department/Employee, data should be filtered as well. How can I achieve this?
There's no need to use the conditional operator at all here... I suspect you want a where clause of:
where opbleftjoin.CmnCalendarYearId == clndrId
&& (empId == 0 || emp.Id == empId)
&& (dptId == 0 || emp.HrmDepartmentId == dptId)
&& (officId != 0 ? emp.HrmOfficeId == officId)
&& emp.CmnCompanyId == CmnId;
Better yet, you could add the conditions in steps - just have the mandatory ones to start with:
var query = from emp in dbContext.EmployeeList
join dsg in dbContext.hrmDesig on emp.HrmDesignationId equals dsg.Id into DsgLeftJoin
from dsgleftjoin in DsgLeftJoin.DefaultIfEmpty()
join opb in dbContext.PfOpeningBalances on emp.Id equals opb.HrmEmployeeId into OpbLeftJoin
from opbleftjoin in OpbLeftJoin.DefaultIfEmpty()
where opbleftjoin.CmnCalendarYearId == clndrId
&& emp.CmnCompanyId == CmnId
select new { emp, dsgleftjoin, opbleftjoin };
if (empId != 0)
{
query = query.Where(x => x.emp.Id == empId);
}
// etc
Also note that your query currently seems to assume that dsgleftjoin and opbleftjoin are non-null, when they could easily be null due to the left join.
Your where condition is wrong, you should try with something like this:
var PFOpeningList = (from emp in dbContext.EmployeeList
join dsg in dbContext.hrmDesig on emp.HrmDesignationId equals dsg.Id into DsgLeftJoin
from dsgleftjoin in DsgLeftJoin.DefaultIfEmpty()
join opb in dbContext.PfOpeningBalances on emp.Id equals opb.HrmEmployeeId into OpbLeftJoin
from opbleftjoin in OpbLeftJoin.DefaultIfEmpty()
where opbleftjoin.CmnCalendarYearId == clndrId
&& (empId != 0 ? emp.Id == empId : true)
&& (dptId != 0 ? emp.HrmDepartmentId == dptId : true)
&& (officId != 0 ? emp.HrmOfficeId == officId : true)
&& emp.CmnCompanyId == CmnId
select new
{
EmployeeId=emp.Id,
EmployeeName=emp.Name,
Designation = dsgleftjoin.Name,
OpeningIncome = (decimal?)opbleftjoin.OpeningIncome,
EmployeeContribution = (decimal?)opbleftjoin.EmployeeContribution,
CompanyContribution = (decimal?)opbleftjoin.CompanyContribution
}).ToList();
The idea is that if your filter parameter is 0, you avoid filtering setting the condition to true

Create a dynamic LINQ Query to cater for different conditions

I have a LINQ query to populate an object (which is then the datasource for a grid) with a few joins.
I want the query to be dynamic so it retrieves rows based on parameters passed, but so far it doesn't work as soon as the StatusID is passed in - it brings back all instances (as if a cartesion product is happening)
_viewfetch.POMastStatusID will either be -1 or a value of 1 or above.
QUERY:
var queryforobject = from p in db.POMasts.AsNoTracking()
join pr in db.Profiles.AsNoTracking() on p.ProfileID equals pr.ID
join c in db.CurrencyTypes.AsNoTracking() on p.CurrencyTypeID equals c.ID
join w in db.WHMasts.AsNoTracking() on p.WarehouseID equals w.ID
join t in db.TermCodeTypes.AsNoTracking() on p.TermCodeTypeID equals t.ID
join s in db.POMastStatusTypes.AsNoTracking() on p.StatusID equals s.ID
//Ensure that these are dynamic
where _viewfetch.VendMastID == -1 || p.VendorID == _viewfetch.VendMastID &&
_viewfetch.POMastStatusID == -1 || p.StatusID == _viewfetch.POMastStatusID
orderby p.ID
//Put the query results into the bespoke object
select new POMastObject { ID = p.ID,
OrderNo = p.OrderNo,
RaisedDate = p.RaisedDate,
RaisedBy = pr.Name,
Currency = c.Description,
Warehouse = w.Description,
Terms = t.Description,
LastEditedBy = p.LastEditedBy,
LastEditedDate = p.LastEditedDate,
Status = s.Name };
if (queryforobject.Count() > 0)
_dataobject = queryforobject.ToList();
Does anyone have any suggestions?
Your query is fine, it's just missing parentheses around the two parts of the && operator:
where (_viewfetch.VendMastID == -1 || p.VendorID == _viewfetch.VendMastID) &&
(_viewfetch.POMastStatusID == -1 || p.StatusID == _viewfetch.POMastStatusID)
Since && has higher precedence than ||, your query effectively evaluates with the two conditions in the middle AND-ed together, like this:
_viewfetch.VendMastID == -1 || (p.VendorID == _viewfetch.VendMastID && _viewfetch.POMastStatusID == -1) || p.StatusID == _viewfetch.POMastStatusID
This is not the logic that you are looking for, because when VendMastID is -1 you get all rows.

Entity framework LINQ speed converting SQL data into C# objects

I have a fairly complex query written in LINQ which queries my database. I have made sure that I am only pulling back the relevant columns from each entity, so the query is as slim as it can be, and therefore the object which LINQ populates does not contain any unnecessary columns either.
If I run the LINQ query's resulting SQL against the DB directly, the SQL runs in about 4 seconds. However, doing this from my LINQ query takes about 25 seconds. The majority of this 25 seconds is taken up by the returned DB data being written into objects.
Are there any useful tricks which will help LINQ/Entity Framework out when performing this part of the operation?
Edit:
The long delay occurs when I call the ToList() method in the query below:
var q1 = from u in etc.Users
where (u.flags & (int)UserFlags.Student) == (int)UserFlags.Student
&& (ariStudents.Contains(u.id) || ariStudents.Count == 0)
&& (from ua in etc.UserAssociations where ua.datasetId == datasetId && ua.userId == u.id && ua.type == (int)UserAssocTypes.EnrolActive select ua).Any()
orderby u.id
select new ElightsRaw2
{
Student = new ElrStudent{StudentId = u.id},
StudentData = (
from sd in etc.StudentDatas
where sd.userId == u.id
&& sd.datasetId == datasetId
select new ElrStudentData { attP = sd.attP, attA = sd.attA, attL = sd.attL }
).FirstOrDefault(),
ElightOverall = (
from els in etc.eLightsStudents
where els.datasetId == datasetId
&& els.userId == u.id
select els
).FirstOrDefault(),
Groups = (
// get all courses and groups for user
from c in etc.Cours
join g in etc.Groups on c.id equals g.courseId
join ua in etc.UserAssociations on g.id equals ua.fkId
where ua.datasetId == datasetId
&& ua.userId == u.id
&& ua.type == (int)UserAssocTypes.EnrolActive
&& (ua.flags & (int)UserAssociationFlags.AssociationDeleted) == 0
&& (c.flags & (int)CourseFlags.Deleted) == 0
select new ElrGroupHolder
{
CourseName = c.name,
GroupName = g.name,
Breakdown = new ElrGroupHolderBreakdown
{
UnitsBelowScoreThresh1 = (
from uus in etc.UserUnitScores
join un in etc.Units on uus.unitId equals un.id
join cu in etc.CourseUnits on un.id equals cu.unitId
where uus.userId == u.id
&& (un.flags & (int)UnitFlags.Deleted) == 0
&& (cu.flags & (int)CourseUnitFlags.NotStarted) == 0
&& cu.courseId == c.id
&& (uus.performance > -1 && uus.performance <= amberThresh)
&& !(from exc in etc.UserAssociations where exc.userId == u.id && exc.fkId == un.id && exc.type == (int)UserAssocTypes.ExcludedUnit select exc).Any() // not excluded from unit
select uus
).Count(),
UnitsBelowScoreThresh2 = (
from uus in etc.UserUnitScores
join un in etc.Units on uus.unitId equals un.id
join cu in etc.CourseUnits on un.id equals cu.unitId
where uus.userId == u.id
&& (un.flags & (int)UnitFlags.Deleted) == 0
&& (cu.flags & (int)CourseUnitFlags.NotStarted) == 0
&& cu.courseId == c.id
&& (uus.performance > -1 && uus.performance <= redThresh)
&& !(from exc in etc.UserAssociations where exc.userId == u.id && exc.fkId == un.id && exc.type == (int)UserAssocTypes.ExcludedUnit select exc).Any() // not excluded from unit
select uus
).Count(),
CfcCount = (
from cfc in etc.CFCs
where cfc.datasetId == datasetId
&& cfc.studentId == u.id
&& cfc.dt > dCfcCutoff
&& cfc.type == (int)CfcTypes.Concern
&& (cfc.flags & (int)CfcFlags.Deleted) == 0
&& (
// only include attendance and behaviour CFCs
(cfc.flags & (int)CfcFlags.Attendance) == (int)CfcFlags.Attendance
|| (cfc.flags & (int)CfcFlags.Behaviour) == (int)CfcFlags.Behaviour
)
select cfc
).Count(),
SrsScores = (
from srs in etc.SRScores
join sr in etc.SubReviews on srs.srId equals sr.id
where sr.datasetId == datasetId
&& (sr.flags & (int)SrFlags.Deleted) == 0
&& (srs.flags & (int)SrsFlags.Deleted) == 0
&& sr.dt > dCfcCutoff
&& sr.userId == u.id
&& sr.courseId == c.id
select new ElrSrScore
{
attainment = srs.attainment,
attitude = srs.attitude,
motivation = srs.motivation,
studyskill = srs.studyskill
}
).ToList(),
ElightEnrolment = (
from ele in etc.eLightsEnrolments
where ele.datasetId == datasetId
&& ele.groupId == g.id
&& ele.userId == u.id
select ele
).FirstOrDefault(),
},
CourseAttendance = (
from a in etc.Attendances
where a.studentId == u.id
&& a.courseId == c.id
&& a.weekNumberId == null
&& a.datasetId == datasetId
select a
).FirstOrDefault()
}
).ToList(),
};
return q1.ToList();
Yes! I ran into something similar myself not to long ago. What I came up with is using the AsParallel() function within LINQ ... however this comes with a few caveats.
You will be running things in parallel - obvious but if your trying to do things in a non thread safe manner there could be issues
This will only be useful in certain cases - the way I got the most use out of it was when I was converting a lot of database rows into C# objects and doing it repetitively ... think foreach,for,while loops that don't have any decision logic in them but just a straight database row to C# class kind of conversion
It really only makes sense for "large" amounts of data - You're going to have to play around with this and see what the timing difference is but if you are just converting a handful of rows, the overhead for AsParallel() will actually cost you more time, not save you any.
Here is some more reading on AsParallel(), hope this helps!
https://msdn.microsoft.com/en-us/library/vstudio/dd413237%28v=vs.100%29.aspx - AsParallel Method
https://msdn.microsoft.com/en-us/library/dd997425%28v=vs.110%29.aspx - Intro to parallel queries
http://www.dotnetperls.com/asparallel - Good basic walkthrough of AsParallel

linq - left outer join with where returning list of nulls

Here is the full query(without the where), that works:
public List<TipoResiduo> filtro(TipoResiduo objent)
{
using (var db = new DBEntities())
{
var consulta = (from a in db.tb006_tipo_residuo
join cr in db.tb016_classe_residuo on a.fk_id_classe_residuo equals cr.id into trcr
from classeresiduo in trcr.DefaultIfEmpty()
join gr in db.tb017_grupo_residuo on a.fk_id_grupo_residuo equals gr.id into trgr
from gruporesiduo in trgr.DefaultIfEmpty()
join tfg in db.tb008_tipo_fonte_geradora on a.fk_id_tipo_fonte_geradora equals tfg.id into trtfg
from tipofontegeradora in trtfg.DefaultIfEmpty()
join civig in db.tb051_categoria_ivig on a.fk_id_categoria_ivig equals civig.id into trci
from categoriaivig in trci.DefaultIfEmpty()
join icap in db.tb048_ibama_capitulo on a.fk_id_ibama_capitulo equals icap.id into tric
from ibamacapitulo in tric.DefaultIfEmpty()
join isubcap in db.tb049_ibama_subcapitulo on a.fk_id_ibama_subcapitulo equals isubcap.id into tris
from ibamasubcapitulo in tris.DefaultIfEmpty()
join ires in db.tb050_ibama_residuo on a.fk_id_ibama_residuo equals ires.id into trir
from ibamaresiduo in trir.DefaultIfEmpty()
//where a.fk_id_classe_residuo == objent.fk_id_classe_residuo
select new TipoResiduo()
{
id = a.id,
no_tipo_residuo = a.no_tipo_residuo,
dt_cadastro = a.dt_cadastro,
fk_id_classe_residuo = a.fk_id_classe_residuo,
fk_id_grupo_residuo = a.fk_id_grupo_residuo,
nu_densidade = a.nu_densidade,
fk_id_tipo_fonte_geradora = a.fk_id_tipo_fonte_geradora,
fk_id_categoria_ivig = a.fk_id_categoria_ivig,
fk_id_ibama_capitulo = a.fk_id_ibama_capitulo,
fk_id_ibama_subcapitulo = a.fk_id_ibama_subcapitulo,
fk_id_ibama_residuo = a.fk_id_ibama_residuo,
no_classe_residuo = classeresiduo == null ? String.Empty : classeresiduo.no_classe_residuo,
no_grupo_residuo = gruporesiduo == null ? String.Empty : gruporesiduo.no_grupo_residuo,
no_tipo_fonte_geradora = tipofontegeradora == null ? String.Empty : tipofontegeradora.no_tipo_fonte_geradora,
no_categoria_ivig = categoriaivig == null ? String.Empty : categoriaivig.no_categoria_ivig,
no_ibama_capitulo = ibamacapitulo == null ? String.Empty : ibamacapitulo.de_ibama_capitulo,
no_ibama_subcapitulo = ibamasubcapitulo == null ? String.Empty : ibamasubcapitulo.de_ibama_subcapitulo,
no_ibama_residuo = ibamaresiduo == null ? String.Empty : ibamaresiduo.de_ibama_residuo
});
return consulta.OrderBy(a => a.no_tipo_residuo).ToList();
}
}
My object TipoResiduo has some virtual fields just for convenience and can have some null fields.
And when I try to filter with the where(removing the //) the query shows nothing. The ObjEnt of the function has some fields previously populated, and when the field is null, I want to show all.
I tried this too, and nothing:
where a.fk_id_classe_residuo ==
(objent.fk_id_classe_residuo == null
? 0 : objent.fk_id_classe_residuo)
I'm new at this, what should I do to make this work?
You have no left outer join so I don't understand the title
If objent.fk_id_classe_residuo is null this will find a.fk_id_classe_residuo = 0 - not all
where a.fk_id_classe_residuo == (objent.fk_id_classe_residuo == null ? 0 : objent.fk_id_classe_residuo)
try this
where objent.fk_id_classe_residuo == null
or a.fk_id_classe_residuo == objent.fk_id_classe_residuo
After hitting my head into the wall, I found the answer:
where objent.fk_id_classe_residuo == 0 ? true : classeresiduo.id == null
&& classeresiduo.id == null ? false : a.fk_id_classe_residuo == objent.fk_id_classe_residuo
The problem is this objent.fk_id_classe_residuo comes from a dropdownlist, and I set this fk_id as 0 when no option is given. Well, would be very difficult to someone help me with this. :|
But I thank Blam for his attention. ;)

why does LINQ To SQL result in SQL like this?

When LINQ translates the below syntax to SQL, the (inner) where clause gets moved to the outer-most query. That's super-unfriendly to the database. I wrote this like Hibernate's HQL (is this appropriate?), and I've written SQL for many moons.
Can anyone help explain what gives, or point me in the way of a resolution?
var rc = (
from dv in (
from dv_j in (
from x in adc.JobManagement
join j in adc.Job on x.JobId equals j.JobId
join js in adc.JobStatus on j.StatusId equals js.JobStatusId
join cm in adc.ClientManagement on j.ClientId equals cm.ClientId
join o in adc.User on cm.UserId equals o.UserId
join jm in adc.JobManagement on j.JobId equals jm.JobId
where
(x.UserId == aid || cm.UserId == aid)
&& (j.StatusDate == null || j.StatusDate >= getFromDate())
&& (jm.ManagementRoleCode == MR_MANAGER)
select new
{
j.JobId,
Job = j.InternalName == null ? j.ExternalName : j.InternalName,
JobStatusDate = j.StatusDate,
JobStatus = js.Code,
Owner = o.Username,
Role = jm.ManagementRoleCode
})
join s in adc.Submission on dv_j.JobId equals s.JobId into dv_s
from s in dv_s.DefaultIfEmpty()
select new
{
dv_j.JobId,
dv_j.Job,
dv_j.JobStatusDate,
dv_j.JobStatus,
dv_j.Owner,
dv_j.Role,
s.SubmissionId,
s.CandidateId,
s.SubmissionDate,
StatusDate = s.StatusDate,
StatusId = s.StatusId
})
join c in adc.Candidate on dv.CandidateId equals c.CandidateId into dv_c
join ss in adc.SubmissionStatus on dv.StatusId equals ss.SubmissionStatusId into dv_ss
from c in dv_c.DefaultIfEmpty()
from ss in dv_ss.DefaultIfEmpty()
orderby
dv.StatusId == null ? dv.StatusDate : dv.JobStatusDate descending,
dv.Job,
c.LastName,
c.NickName,
c.FirstName
select new Projects
{
Id = dv.JobId,
Project = dv.Job,
Submitted = dv.SubmissionDate,
Candidate = FormatIndividual(c.LastName, c.FirstName, c.NickName),
Status = dv.StatusId == null ? ss.Code : dv.JobStatus,
StatusDate = dv.StatusId == null ? dv.StatusDate : dv.JobStatusDate,
Role = dv.Role,
Owner = dv.Owner
});
Try breaking down the one statement into two. This would work as it cannot move the where to a place that doesn't exist yet. This does make multiple round trips to the database, but it is better than having most of several large tables being joined then culled. I would try this:
var inMemoryTable = (
from x in adc.JobManagement
join j in adc.Job on x.JobId equals j.JobId
join js in adc.JobStatus on j.StatusId equals js.JobStatusId
join cm in adc.ClientManagement on j.ClientId equals cm.ClientId
join o in adc.User on cm.UserId equals o.UserId
join jm in adc.JobManagement on j.JobId equals jm.JobId
where
(x.UserId == aid || cm.UserId == aid)
&& (j.StatusDate == null || j.StatusDate >= getFromDate())
&& (jm.ManagementRoleCode == MR_MANAGER)
select new
{
j.JobId,
Job = j.InternalName == null ? j.ExternalName : j.InternalName,
JobStatusDate = j.StatusDate,
JobStatus = js.Code,
Owner = o.Username,
Role = jm.ManagementRoleCode
});
var rc = (
from dv in (
from dv_j in inMemoryTable
join s in adc.Submission on dv_j.JobId equals s.JobId into dv_s
from s in dv_s.DefaultIfEmpty()
select new
{
dv_j.JobId,
dv_j.Job,
dv_j.JobStatusDate,
dv_j.JobStatus,
dv_j.Owner,
dv_j.Role,
s.SubmissionId,
s.CandidateId,
s.SubmissionDate,
StatusDate = s.StatusDate,
StatusId = s.StatusId
})
join c in adc.Candidate on dv.CandidateId equals c.CandidateId into dv_c
join ss in adc.SubmissionStatus on dv.StatusId equals ss.SubmissionStatusId into dv_ss
from c in dv_c.DefaultIfEmpty()
from ss in dv_ss.DefaultIfEmpty()
orderby
dv.StatusId == null ? dv.StatusDate : dv.JobStatusDate descending,
dv.Job,
c.LastName,
c.NickName,
c.FirstName
select new Projects
{
Id = dv.JobId,
Project = dv.Job,
Submitted = dv.SubmissionDate,
Candidate = FormatIndividual(c.LastName, c.FirstName, c.NickName),
Status = dv.StatusId == null ? ss.Code : dv.JobStatus,
StatusDate = dv.StatusId == null ? dv.StatusDate : dv.JobStatusDate,
Role = dv.Role,
Owner = dv.Owner
});

Categories

Resources