Why LINQ can't pick up the null value C# - c#

I try to use LINQ to filter the data, the data is from 3rd party API (JIRA Server), and ResolutionDateis DateTime type, I guess it use Nullable, anyway, I am pretty sure the value is null, but when I use LINQ, it just not work at all. The LINQ just can't do i.ResolutionDate == null, it always said there is no item match this condition. I'm pretty sure I have the issues their ResolutionDate is null.
https://developer.atlassian.com/server/jira/platform/database-issue-fields/
var foo = datas.Where(i =>
i.Created > date && i.Created <= date.AddDays(7) &&
i.ResolutionDate> date.AddDays(7) && i.ResolutionDate== null);

You could probably coalesce those into (i.ResolutionDate?.Date > date.AddDays(7))
Ultimately, it should have some condition that will return true when you do the comparison.

You should check if the value of ResolutionDate is null OR more than seven days in the future
var foo = datas.Where(i =>
i.Created > date && i.Created <= date.AddDays(7) &&
(i.ResolutionDate == null || i.ResolutionDate > date.AddDays(7)));

Related

Entity Framework Core where clause extra condiition

I have this simple query, the problem is that the End property is DateTime? type and I would like to include the records where this value is null as well but I cannot seem to do it. I tried using the Terniary operator and still no results
await _context.Registos
.Where(r => r.Start.Date >= DateStart.Date && r.End.HasValue ? r.End.Value <= DateEnd.Date : !r.End.HasValue )
.AsNoTracking()
.ToListAsync();
A cleaner way, something like this:
await _context.Registos
.Where(r => r.Start.Date >= DateStart.Date
&& (r.End == null || r.End.Value <= DateEnd.Date))
.AsNoTracking()
.ToListAsync();
await _context.Registos
.Where(r => r.Start.Date >= DateStart.Date &&
(!r.End.HasValue || (r.End.Value <= DateEnd.Date)) )
.AsNoTracking()
.ToListAsync();
The only way of having a variable which hasn't been assigned a value in C# is for it to be a local variable - in which case at compile-time you can tell that it isn't definitely assigned by trying to read from it :)
I suspect you really want Nullable<DateTime> (or DateTime? with the C# syntactic sugar) - make it null to start with and then assign a normal DateTime value (which will be converted appropriately). Then you can just compare with null (or use the HasValue property) to see whether a "real" value has been set.

LINQ query needed using a conditional operand in the WHERE clause

I am having trouble composing a LINQ statement that uses a conditional operand within the where clause and have looked through this site for a similar problem without any luck. I'm sure there is a better way to express this query. The value XXX within the is the result of determining which field in the object to use for comparison and is explained below.
Below is what I am trying to accomplish:
var paymentReceivedAmt = (from registerEntry in RegisterEntries
where registerEntry.TransactionType != null
&& registerEntry.TransactionType.Id.SubsystemCode == "A"
&& registerEntry.Receipt != null
&& registerEntry.PostDate != null
&& XXX >= lastInvoicedDate
select registerEntry.TransactionAmount.GetValueOrDefault(0)).Sum();
Value XXX =
if registerEntry.AddedDate = registerEntry.PostDate
registerEntry.AddedDate
else
registerEntry.PostDate
The values registerEntry.AddedDate and registerEntry.PostDate are DateTime type, however when comparing I need to only compare the date and not the time
Does anyone have any idea on how to do this?
Why not just use registerEntry.PostDate for XXX? If it is equal to registerEntry.AddedDate, might as well use it and simplify the whole thing
var paymentReceivedAmt = (from registerEntry in RegisterEntries
where registerEntry.TransactionType != null
&& registerEntry.TransactionType.Id.SubsystemCode == "A"
&& registerEntry.Receipt != null
&& registerEntry.PostDate != null
&& registerEntry.PostDate >= lastInvoicedDate
select registerEntry.TransactionAmount.GetValueOrDefault(0)).Sum();
Depending on the LINQ provider you're using you can try the ternary operator:
var paymentReceivedAmt = (from registerEntry in RegisterEntries
where registerEntry.TransactionType != null
&& registerEntry.TransactionType.Id.SubsystemCode == "A"
&& registerEntry.Receipt != null
&& registerEntry.PostDate != null
&& (registerEntry.AddedDate == registerEntry.PostDate
? registerEntry.AddedDate
: registerEntry.PostDate) >= lastInvoicedDate
select registerEntry.TransactionAmount.GetValueOrDefault(0)).Sum();

Null value in linq where clause

I'm having an issue where I want to return results where something matches and I get an error if one of the properties I'm trying to match is null.
if (!string.IsNullOrEmpty(searchString))
{
Infos = Infos.Where(
x =>
x.FirstName.ToLower().Contains(searchString) ||
x.LastName.ToLower().Contains(searchString) ||
x.ContractNum.ToLower().Contains(searchString) ||
x.VIN.ToLower().Contains(searchString) ||
x.Claim.InitiatedBy.ToLower().Contains(searchString)
).ToList();
}
If ContractNum or VIN, for example, are null then it throws an error. I'm not sure how to check if one of these are null inside of a linq query.
You can add explicit null checks:
Infos = Infos.Where(
x =>
(x.FirstName != null && x.FirstName.ToLower().Contains(searchString)) ||
(x.LastName != null && x.LastName.ToLower().Contains(searchString)) ||
(x.ContractNum != null && x.ContractNum.ToLower().Contains(searchString)) ||
(x.VIN != null && x.VIN.ToLower().Contains(searchString)) ||
(x.Claim != null && x.Claim.InitiatedBy != null && x.Claim.InitiatedBy.ToLower().Contains(searchString))
).ToList();
You have multiple options, first is to do an explicit check against null and the other option is to use Null propagation operator.
x.FirstName != null && x.FirstName.ToLower().Contains(searchString)
or
x.FirstName?.ToLower()?.Contains(searchString) == true
But I would suggest you to use IndexOf instead of Contains for case
insensitive comparison.
something like:
x.FirstName?.IndexOf(searchString, StringComparison.CurrentCultureIgnoreCase) >= 0)
Checking the property is null or empty before comparing it it's the only way I know
if (!string.IsNullOrEmpty(searchString))
{
Infos = Infos.Where(
x =>
(!String.IsNullOrEmpty(x.FirstName) && x.FirstName.ToLowerInvariant().Contains(searchString)) ||
(!String.IsNullOrEmpty(x.LastName) && x.LastName.ToLowerInvariant().Contains(searchString)) ||
(!String.IsNullOrEmpty(x.ContractNum) && x.ContractNum.ToLowerInvariant().Contains(searchString)) ||
(!String.IsNullOrEmpty(x.VIN) && x.VIN.ToLowerInvariant().Contains(searchString)) ||
(x.Claim != null && !String.IsNullOrEmpty(x.Claim.InitiatedBy) && x.Claim.InitiatedBy.ToLowerInvariant().Contains(searchString))
).ToList();
}
EXTRA: I added a check on the Claim property to make sure it's not null when looking at InitiatedBy
EXTRA 2: Using the build in function IsNullOrEmpty to compare string to "" and nullso the code is clearer.
Extra 3: Used of ToLowerInvariant (https://msdn.microsoft.com/en-us/library/system.string.tolowerinvariant(v=vs.110).aspx) so the lowering action will act the same no matter of the culture.
You could use ?? to replace it with a acceptable value.
(x.ContractNum??"").ToLower()
I would use the null conditional operator ?, this will however, return a nullable bool? so you will need to handle that appropriately.
Some examples on how to do this:
x?.FirstName?.ToLower().Contains(searchString) == true;
x?.FirstName?.ToLower().Contains(searchString) ?? false;
An alternative method to keep the comparison logic in one place to use a sub collection of the properties and check on those:
Infos = Infos.Where(i=>
new[] {i.FirstName,i.LastName,i.ContractNum /*etc*/}
.Any(w=> w?.ToLower().Contains(searchString) ?? false))
.ToList();
(It does read out all properties, but that shouldn't cost much performance and gains much maintainability )

How do I check if a date is null from within a lambda expression and use todays date only if it is null

So I have two columns. a date_from which will never be null and a date_to which can be null.
When it is null I want to use today's date instead of null. When it is not null I want to use the date of the column.
Here is the lambda I am using.
serv_plus_Addons MarkupOnParts = db.serv_plus_Addons.Where(w =>
w.addon_name.ToLower() == "markup on parts"
&& w.sdealer_number == sdealer_number
&& w.date_to <= dtcontract_sale_date
&& w.date_from >= dtcontract_sale_date
).FirstOrDefault();
use null coalescence ?? Operator (C# Reference)
w.date_to ?? DateTime.Today
which would mean that if date_to is not null use date_to otherwise use DateTime.Today
another way is via
w.date_to != null ? w.date_to : DateTime.Today

Filter list by date and time MVC/C#

I'm trying to filter a list according to give start and end date, sometimes it does give me proper rows according to the info I've entered, sometimes not. Below is my query does anybody see any problem in logic?
public List<MyTicket> FilteredTickets => Tickets.Where(x =>
(string.IsNullOrEmpty(TicketType) || x.RequestTypeId == TicketType) &&
(StartDate == null || x.DateLogged >= StartDate) && (EndDate == null || x.DateLogged <= EndDate)).ToList();
You need to fix as follows:
public List<MyTicket> FilteredTickets =
Tickets.Where(x =>
(!string.IsNullOrEmpty(TicketType) && x.RequestTypeId == TicketType) &&
(StartDate != null && x.DateLogged >= StartDate) &&
(EndDate != null && x.DateLogged <= EndDate)).ToList();
You are currently checking if your StartDate and EndDate values are null or greater instead of not null and greater :
public List<MyTicket> FilteredTickets => Tickets.Where(x =>
(string.IsNullOrEmpty(TicketType) || x.RequestTypeId == TicketType) &&
(StartDate != null && x.DateLogged >= StartDate) &&
(EndDate != null && x.DateLogged <= EndDate))
.ToList();
So as soon as your previous expression was being evaluated, it would see that one of these date fields was null and evaluate the entire section as true, thus displaying the result as opposed to filtering it out.
It's a dropdown list so it has to allow the user to leave it blank (null) so that wasn't an error, but apparently the problem is since it was invoking the get method, instead of the post, it was getting confused with date and time format. I've found some of the answers about setting up the global settings and culture in order to solve this problem. MVC DateTime binding with incorrect date format

Categories

Resources