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.
Related
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
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!)
I am have an issue with a linq query. I am joining two tables but the where clauses are being completely ignored.
using (var db = new Context())
{
var count = (from c in db.PERSON
join dt in db.DATA_INPUT_CHANGE_LOG
on c.DataInputTypeId equals dt.DataInputTypeId
join x in db.DATA_INPUT_CHANGE_LOG
on c.Id equals x.DataItemId
where c.PersonId == p1Id &&
c.RefPersonId == p2Id &&
c.RelationshipId == rId
where x.Approved
where x.Checked
where x.Hidden == false
select c).Count();
return count > 0;
}
In this particular query the x.Approved, x.Checked and x.Hidden == false where clauses are completely ignored.
Can anyone point me in the right direction?
Your syntax is incorrect. You should only have one where clause. See below:
var count = (from c in db.PERSON
join dt in db.DATA_INPUT_CHANGE_LOG
on c.DataInputTypeId equals dt.DataInputTypeId
join x in db.DATA_INPUT_CHANGE_LOG
on c.Id equals x.DataItemId
where c.PersonId == p1Id &&
c.RefPersonId == p2Id &&
c.RelationshipId == rId &&
x.Approved &&
x.Checked &&
x.Hidden == false
select c).Count();
return count > 0;
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
I have a LINQ2SQL statement where I am using two criteria:
var query1 = from r in dt.Test
where r.ID == 92
&& r.Status = '"I"
select r.ID && r.Status = "I"
But its giving me an err that AND (&&) operator cannot work with string and bool. Whats the turnaround for this?
Try replacing your = signs with ==
var query1 = from r in dt.Test
where r.ID == 92
&& r.Status == "I"
select r.ID && r.Status == "I"
Remember that = in C# is the assignment operator, and == is the equality operator. As someone who regularly flips between C# and VB.NET, I often come unstuck here!
You have a single equals sign r.Status = '"I", should be r.Status == '"I"
You mean == in place of =; the assignment expression (as opposed to the equality operator) is confusing things; instead of returning a bool, the result of r.Status = "I" is a string... "I"
var query1 = from r in dt.Test
where r.ID == 92 && r.Status == "I"
select r.ID;
(not quite sure what to make of the last part of your select, so I omitted it)
= is used for assignment and == is used for equality.
I am not sure what result you're expecting, but select r.ID && r.Status == "I" (even with 2 equal signs) is not valid in any case.
Depending on what you want to select, if the result is the amount of the rows qualifying for your search consider using Count().
If you want to select these two values, use a POCO class or an anonymous type:
var query1 = from r in dt.Test
where r.ID == 92 && r.Status == "I"
select new { ID = r.ID, Status = r.Status };
var query1 = from r in dt.Test
where r.ID == 92 && r.Status == "I"
select r.ID && r.Status == "I";