This is my linq query.
var data =
(from obj in lstEventsDataForGrid
where obj.strDateCode.Contains(thisWeekend[0] == null ? "" : thisWeekend[0])
|| obj.strDateCode.Contains(thisWeekend[1] == null ? "$" : thisWeekend[1])
|| obj.strDateCode.Contains(thisWeekend[2] == null ? "$" : thisWeekend[2])
&& strArr.Contains(obj.strEventType.ToString().ToUpper())
orderby obj.dtmStartDate ascending
select obj).GroupBy(x => x.strEventCode)
.Select(y => y.First()).ToArray();
Expected Result
It should not come whether the strEventType is not in the strArr.
But it is coming even that type is not in the array.
Issue I noticed is if I remove one where condition i.e that obj.strDateCode.Contains(...) the other condition is working.
Where am I going wrong? Please suggest something!
I rewrote your query using null-coalesce operators to make it more readable. I also added line numbers to point out what I think is wrong here:
1. var data = (
2. from obj in lstEventsDataForGrid
3. where obj.strDateCode.Contains(thisWeekend[0] ?? "") ||
4. obj.strDateCode.Contains(thisWeekend[1] ?? "$") ||
5. obj.strDateCode.Contains(thisWeekend[2] ?? "$") &&
6. strArr.Contains(obj.strEventType.ToString().ToUpper())
7. orderby obj.dtmStartDate ascending
8. select obj
9. ).GroupBy(x => x.strEventCode).Select(y => y.First()).ToArray();
You need to change the following lines:
3. where (obj.strDateCode ... // add '('
5. ... thisWeekend[2] ?? "$")) && // add ')'
This way, your && will overpower the rest of the conditions.
I think you're missing some parentheses. Do you mean to treat the three || conditions as one option? As in
where (A || B || C) && D
Try put one after where here:
where (obj.strDateCode.Contains(thisWeekend[0]
and a second one here:
: thisWeekend[2]))
Your where predicate contains an error:
obj.strDateCode.Contains(thisWeekend[0] == null ? "" : thisWeekend[0])
|| obj.strDateCode.Contains(thisWeekend[1] == null ? "$" : thisWeekend[1])
|| obj.strDateCode.Contains(thisWeekend[2] == null ? "$" : thisWeekend[2])
&& strArr.Contains(obj.strEventType.ToString().ToUpper())
This is an expression of the form:
where Condition1 || Condition2 || Condition3 && Condition4.
In C#, the && operator takes precedence over the || operator, so this is equivalent to
where Condition1 || Condition2 || (Condition3 && Condition4).
In this situation, Condition4 is only evaluated if Condition3 is true. If Condition1 or Condition2 are true, the entire predicate will return true and the remainder of the expression will short-circuit.
What you probably intended was:
where (Condition1 || Condition2 || Condition3) && Condition4
Or, extended to your example:
(obj.strDateCode.Contains(thisWeekend[0] == null ? "" : thisWeekend[0])
|| obj.strDateCode.Contains(thisWeekend[1] == null ? "$" : thisWeekend[1])
|| obj.strDateCode.Contains(thisWeekend[2] == null ? "$" : thisWeekend[2])
) && strArr.Contains(obj.strEventType.ToString().ToUpper())
This will ensure that an obj will not be returned if it is not contained within strArr,
which your question indicates is the required result.
Related
I have a complex where clause in my EF linq statement which repeats a subquery expression, on _db.OPESRRecoveryElements, but with different parameters, one of which is depending on records from the main entity, OPCases/OPCaseDto.
The query as it is works, but its hard for people to read. Ideally I'd like to be able to create an expression which could be re-used at the 3 necessary points and would still allow it to execute as a single, server-side SQL statement.
Is there a way to create an Expression / IQueryable definition which can be used for a subquery like this?
List<OPCaseDto> opCases = await _db.OPCases
.ProjectTo<OPCaseDto>(_autoMapperConfig, null, requestedExpands)
.Where(c =>
c.OPStatusId == OPStatusIds.AwaitingRecoveryElement
&& (
(c.OPCategoryLetter == "B"
// Only need a gross pensionable element if there is an outstanding gross pensionable figure
&& (c.GrossOverpaidPensionable - c.GrossRecoveredPensionable == 0
|| _db.OPESRRecoveryElements.Any(e => !e.NonPensionable && e.OPRecoveryMethod.OPTypeLetter == "G"
&& !e.OPRecoveryPlans.Any(rp
=> (rp.RecoveryStatus == OPRecoveryStatuses.NotStarted || rp.RecoveryStatus == OPRecoveryStatuses.InRecovery)
&& rp.AssignmentNo == c.RecoveryAssignmentNo)))
// Only need a gross non-pensionable element if there is an outstanding gross non-pensionable figure
&& (c.GrossOverpaidNonPensionable - c.GrossRecoveredNonPensionable == 0
|| _db.OPESRRecoveryElements.Any(e => e.NonPensionable && e.OPRecoveryMethod.OPTypeLetter == "G"
&& !e.OPRecoveryPlans.Any(rp
=> (rp.RecoveryStatus == OPRecoveryStatuses.NotStarted || rp.RecoveryStatus == OPRecoveryStatuses.InRecovery)
&& rp.AssignmentNo == c.RecoveryAssignmentNo))))
|| (c.OPCategoryLetter == "D"
// Don't need to check for an outstanding net figure - if the case is net and isn't complete, there will be one!
&& _db.OPESRRecoveryElements.Any(e => e.OPRecoveryMethod.OPTypeLetter == "N"
&& !e.OPRecoveryPlans.Any(rp
=> (rp.RecoveryStatus == OPRecoveryStatuses.NotStarted || rp.RecoveryStatus == OPRecoveryStatuses.InRecovery)
&& rp.AssignmentNo == c.RecoveryAssignmentNo)))
)
)
.AsNoTracking()
.ToListAsync();
If it wasn't for the c.RecoveryAssignmentNo part, I could easily create an expression like:
public Expression<Func<OPESRRecoveryElement, bool>> NoActiveRecoveryPlans(string opType, bool nonPen)
{
return e => e.OPRecoveryMethod.OPTypeLetter == opType
&& e.NonPensionable == nonPen
&& !e.OPRecoveryPlans.Any(rp
=> (rp.RecoveryStatus == OPRecoveryStatuses.NotStarted || rp.RecoveryStatus == OPRecoveryStatuses.InRecovery));
}
and use it like:
(c.OPCategoryLetter == "B"
// Only need a gross pensionable element if there is an outstanding gross pensionable figure
&& (c.GrossOverpaidPensionable - c.GrossRecoveredPensionable == 0
|| _db.OPESRRecoveryElements.Any(NoActiveRecoveryPlans("G", false)))
and it would get executed before the query to get the OPCases.
I could also fetch all the OPCaseDto records and OPESRRecoveryElements as separate queries and filter in memory, but I don't want to do that.
If I add a parameter to the function, string assignmentNo, I (unsurprisingly) get an error - "Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpression3' to type 'System.Linq.Expressions.LambdaExpression'"
I have a query that in T-SQL it is
SELECT *
FROM rpm_scrty_rpm_usr ru
WHERE ru.inact_ind = 'N'
AND email_id IS NOT NULL
AND wwid IS NULL
AND LTRIM(RTRIM (email_id)) <> ''
AND dflt_ste_id NOT IN (25,346,350,352,353,354,355,357,358,366,372,411)
When I have been converting it to LINQ, I have everything except the "NOT IN"
var querynonSystem = (from ru in Rpm_scrty_rpm_usrs
where ru.Inact_ind == "N" && ru.Email_id != null && ru.Wwid == null && ru.Email_id.Trim() != ""
&& ru.Dflt_ste_id != 25
select ru).Count();
I did temporarily put in this line && ru.Dflt_ste_id != 25
However I need to have AND dflt_ste_id NOT IN (25,346,350,352,353,354,355,357,358,366,372,411)
I am seeing a lot of different code like
this lambda where !(list2.Any(item2 => item2.Email == item1.Email))
Then var otherObjects = context.ItemList.Where(x => !itemIds.Contains(x.Id));
For my linq query, how can I do this Not In in simple manner?
You can use Contains with !. In addition, if you just want to count rows, you can use Count.
var ids = new List<int> {25, 346, 350, 352, 353, 354, 355, 357, 358, 366, 372, 411};
var querynonSystem = XXXcontext.Rpm_scrty_rpm_usrs.Count(x =>
x.Inact_ind == "N" &&
x.Email_id != null &&
x.Wwid == null &&
x.Email_id.Trim() != "" &&
!ids.Contains(x.Dflt_ste_id));
From comment: if you want to retrieve all, you can still use Where and Select.
var querynonSystem = XXXcontext.Rpm_scrty_rpm_usrs.Where(x =>
x.Inact_ind == "N" &&
x.Email_id != null &&
x.Wwid == null &&
x.Email_id.Trim() != "" &&
!ids.Contains(x.Dflt_ste_id)).Select(x => x).ToList();
FYI: you cannot call Rpm_scrty_rpm_usrs table class to query. Instead, you need DbContext or some other repository.
There is no "not in" operator unless the type of the query is the same as the type you want to filter against (in which case you could use except). Here it is not. You're working on an IEnumerable and you want to filter on it's ID so a list of int. The where with lambda and contains is your best bet and WILL be translated to an in on the SQL side by most providers.
var FilterIds = new List<int>{1,2,3,4,344,3423525};
var querynonSystem = (from ru in Rpm_scrty_rpm_usrs
where ru.Inact_ind == "N" && ru.Email_id != null && ru.Wwid == null && ru.Email_id.Trim() != ""
&& ru.Dflt_ste_id != 25
select ru)
// Use this
.Where(ru=>!FilterIds.Any(id=>ru.dflt_ste_id ==id))
// Or this
.Where(ru=>!FilterIds.Contains(ru.dflt_ste_id))
.Count();
I am new to EF and trying to do a small project with it. I added a condition to EF but I am having a problem.
My condition is all about IN condition like SQL,
SELECT * FROM table1 WHERE col1 IN (1,2,3...)
Here is my EF....
var res3 = res2.Where(l => !slitDetail
.Any(s => s.BlockId == l.Id
&& s.WarehouseDepot.WarehouseDepotName != "Ara Ürün Depo"
&& s.WarehouseDepot.WarehouseDepotName != "Özel Kesim Depo"));
s.WarehouseDepot might be NULL sometimes which is normal, but if it is null, this query throws an exception.
How can I check if s.WarehouseDepot is null and make it work even if it is null?
There are 2 possiblities if s.WarehouseDepot == null
1) You want your Any to return true, in that case you could use something like
var res3 = res2.Where(l => !slitDetail
.Any(s => s.BlockId == l.Id
&& s.WarehouseDepot != null
? (s.WarehouseDepot.WarehouseDepotName != "Ara Ürün Depo" && s.WarehouseDepot.WarehouseDepotName != "Özel Kesim Depo")
: true));
This would use the s.WarehouseDepot only if it has a value otherwise it would return true
2) You want your Any to return false. In this case you could simply replace the true by false in the above expression or use something like
var res3 = res2.Where(l => !slitDetail
.Any(s => s.BlockId == l.Id
&& s.WarehouseDepot != null
&& s.WarehouseDepot.WarehouseDepotName != "Ara Ürün Depo"
&& s.WarehouseDepot.WarehouseDepotName != "Özel Kesim Depo"));
Note that both these outcomes will automatically consider the s.BlockId == l.Id condition too.
i want to do the following IF statement,
if (checkID.Equals(Convert.ToInt32(txtCheck.Text))
&& drop == 319020000
|| currentFloor[id][0].checkFlag == 1)
what i want to check here it the following thing:
i want to check if this whole statement is true
checkID.Equals(Convert.ToInt32(txtCheck.Text)) && drop == 319020000`
or this statment:
currentFloor[id][0].checkFlag == 1
If 1 of them is true it should go inside the loop.
What am i doing wrong here?
Use parentheses, you have many operators at the same level and precedence may be killing you
if ((checkID.Equals(Convert.ToInt32(txtCheck.Text)) && drop == 319020000)
|| currentFloor[id][0].checkFlag == 1)
http://msdn.microsoft.com/en-us/library/aa691323(v=vs.71).aspx
;)
you have to use additional parentheses like follows,
if ((checkID.Equals(Convert.ToInt32(txtCheck.Text)) && drop == 319020000) || currentFloor[id][0].checkFlag == 1)
Well,
I am not sure if I am wrong or if the linq parsed mistakes, but the following linq query returns what I DON'T want if I don't use additional parenthesis.
int? userLevel;
Guid? supervisorId;
List<int> levelsIds = new List<int>();
string hierarchyPath;
// init the vars above
// ...
var qry = from f in items
where userLevel.HasValue
? (f.IsMinLevelIdNull() || (levelsIds.Contains(f.MinLevelId)))
: true
&& supervisorId.HasValue
? (f.IsSupervisorIdNull() || (!f.ChildrenVisibility && (f.SupervisorId == supervisorId.Value))
|| (f.ChildrenVisibility && (hierarchyPath.IndexOf(f.SupervisorId.ToString()) >= 0)))
: true
select f;
The idea here is to run a query in AND between two blocks of conditions 'activated' by the presence of the variables 'userLevel' and 'supervisorId'.
For example, if both userLevel and supervisoId are null the query becomes:
var qry = from f in items
where true && true
select f;
Well, this query works well only if I enclose in additional parentheses the 2 trigraphs:
var qry = from f in items
where (userLevel.HasValue
? (f.IsMinLevelIdNull() || (levelsIds.Contains(f.MinLevelId)))
: true)
&& (supervisorId.HasValue
? (f.IsSupervisorIdNull() || (!f.ChildrenVisibility && (f.SupervisorId == supervisorId.Value))
|| (f.ChildrenVisibility && (hierarchyPath.IndexOf(f.SupervisorId.ToString()) >= 0)))
: true)
select f;
The question is: why the extra parenthesis are required? My opinion is that there is a problem in the linq parser.
From 7.2.1 Operator precedence and associativity && gets evaluated before ? :
The additional parentheses would be required as the precedence is evaluated in the wrong order for example your code would be evaluated as the following because there is no break between true && supervisorId.HasValue...
var qry = from f in items
where
1st: userLevel.HasValue
?
2nd: (f.IsMinLevelIdNull() || (levelsIds.Contains(f.MinLevelId)))
:
3rd: true && supervisorId.HasValue
? (f.IsSupervisorIdNull() || (!f.ChildrenVisibility && (f.SupervisorId == supervisorId.Value))
|| (f.ChildrenVisibility && (hierarchyPath.IndexOf(f.SupervisorId.ToString()) >= 0))) **)**
: true
select f;