How to check if object is null in EF - c#

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.

Related

C# Linq to EF Separate Subquery into Expression

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'"

Why am I getting a "Sequence contains no matching element" error when using .Any

I have a .Any() Linq Method:
db.MyTable.Any(x => x.Year == MyObj.Year && x.Quarter == MyObj.Quarter && x.Week == MyObj.Week)
That is returning the error:
System.InvalidOperationException occurred
HResult=0x80131509
Message=Sequence contains no matching element
Source=EntityFramework
However the MSDN documentation states that the .Any method returns "true if the source sequence contains any elements; otherwise, false."
Why is this method throwing the exception instead of returning False?
With this little code it is fairly difficult to see what the cause is. It certainly is not in this part of the code.
Try to do some debugging, use the debugger to check all values, or write some Debugging statements before you perform your function:
// Check myObj
MyObjectType myObj = ... // instead of var, so you are certain you have the right type
Debug.Assert(myObj != null);
// only if Year, Quarter, Week are classes:
Debug.Assert(myObj.Year != null);
Debug.Assert(myObj.Quarter != null);
Debug.Assert(myObj.Week != null);
// check your db:
Debug.Assert(db != null);
Debug.Assert(db.MyTable != null);
int count1 = db.MyTable.Count();
int count2 = db.MyTable
.Where(x => x.Year == MyObj.Year
&& x.Quarter == MyObj.Quarter
&& x.Week == MyObj.Week)
.Count();
bool hasAny = db.MyTable
.Where(x => x.Year == MyObj.Year
&& x.Quarter == MyObj.Quarter
&& x.Week == MyObj.Week)
.Any();
// if all this works, your statement should also work
hasAny = db.MyTable
.Any(x => x.Year == MyObj.Year
&& x.Quarter == MyObj.Quarter
&& x.Week == MyObj.Week);
Is hard to see, with your example but probably you must check if you have Null values in "MyTable" and the datatypes of MyTable.Year,MyTable.Quarter and MyTable.Week match with the sames in MyObj...

This function can only be invoked from LINQ to Entities. .All()

I have a List property that I am setting like so:
testCard.LstSummaries =
db.Summaries.Where(
x =>
(x.AID == aId || x.AInformation.RegNumber == aRegNumber) && DbFunctions.TruncateTime(x.Day) == DateTime.Today.Date &&
x.deleted == false).ToList();
Then I have a conditional statement:
if (testCard.LstSummaries.Count > 0)
{
if (
testCard.LstSummaries.All(
x =>
(x.AID == aId || // ERROR HAPPENS ON THIS LINE
x.AInformation.RegNumber == aRegNumber) &&
DbFunctions.TruncateTime(x.Day) == DateTime.Today.Date && x.deleted == false))
{
// .... do something
}
I get an error:
This function can only be invoked from LINQ to Entities.
I want to avoid to make multiple calls to the database.. furthermore testCard.LstSummaries already has the values I am looking for.. but if I do this:
if (testCard.LstSummaries.Count > 0)
{
if (
db.Summaries.All(
x =>
(x.AID == aId || // NO ERROR
x.AInformation.RegNumber == aRegNumber) &&
DbFunctions.TruncateTime(x.Day) == DateTime.Today.Date && x.deleted == false))
{
// .... do something
}
I feel like making this call to the database is pointless because I would be retrieving the same results that are already stored in testCard.LstSummaries, but I can't invoke .All() because it's not LINQ to Entities.
Is there a workaround for this?
Problem is with DbFunctions.TruncateTime(x.Day), because it is converted to sql on runtime. Try to check without it.

LINQ equivalent of SQL NOT IN statement

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();

How to use array in where condition in Linq queries

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.

Categories