C# Lambda returns some null values - c#

opencall.Priority =
averages.Where(x => x.ProblemCode == opencall.ProblemCode)
.SingleOrDefault().Priority;
The above lambda statement returns some nulls because ProblemCode isn't always guaranteed to be in the averages list.
How can I rewrite this statement so that if that is the case opencall.Priority is set to "" instead of the application throwing an error?

You have to provide a new default value for your reference type, other than null.
opencall.Priority = averages.Where(x => x.ProblemCode == opencall.ProblemCode)
.Select(x => x.Priority)
.DefaultIfEmpty("")
.Single();
So Priority is a string? Note that you don't need SingleOrDefault anymore since the query can never throw an exception, because it will return your provided fallback value.

Split it up:
var result = averages.Where(x => x.ProblemCode == opencall.ProblemCode).SingleOrDefault()
opencall.Priority = result != null ? result.Priority : string.Empty;

Try getting the problem code first, then check if it's null.
var possiblyNullProblemCode=
averages.Where(
x => x.ProblemCode == opencall.ProblemCode)
.SingleOrDefault();
openCall.Priority =
possiblyNullProblemCode == null ?
string.Empty :
possiblyNullProblemCode.Priority;

Assuming Priority is string, you could try:
var average = averages.Where(x => x.ProblemCode == opencall.ProblemCode).SingleOrDefault()
opencall.Priority = average == null ? "" : average.Priority;

You can simply write:
opencall.Priority =
averages.Where(x => x.ProblemCode == opencall.ProblemCode)
.Select(x => x.Priority)
.SingleOrDefault() ?? string.Empty;

Related

How to check if column value has "value"

I want to check if value of "Acceptance" is "Accepted" and if it has that value- .Sum else i want to get 0, but have some problms with finding correct syntax. I cant get "Acceptance" value
My method
public decimal Prices2(string term)
{
var kl= db.Order.Where(x => x.Client == term && x.Acceptance == "Accepted");
if (term != null && kl.Acceptance == "Accepted" )
{ ^^//Element does not contain definition"Acceptance"
return kl.Sum(x => x.Price);
}
else
{
return 0;
}
}
how I get "term"
public IEnumerable<string> GetClient(string term)
{
return db.Order.Where(x => (term != null && x.Client.Contains(term)) || (term == null)).OrderBy(c => c.Client).Take(10).Select(a => a.Client).Distinct();
}
When i try this:
return db.Order.Where(x => x.Client == term && x.Acceptance == "Accepted").sum(x=>x.Price)
I get error when there is no "Accepted" order for client
System.InvalidOperationException: „The cast to value type 'System.Decimal' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type.”
How can i check first if there is Accepted order for client and return 0 if there istn?
First Assign the query to one variable,
var orders = db.Order.Where(x => x.Client == term && x.Acceptance == "Accepted");
var result= orders.Count() > 0 ? orders.Sum(x=>x.Price) : 0.0M;
return result;
You're return type of method should be decimal
.
First of all, your code will not work because variable kl is of type IEnumerable<Order> which doesn't have a property Acceptance.
The code mentioned by #uk2k05 in the comments section will solve your problem:
return db.Order
.Where(x => x.Client == term && x.Acceptance == "Accepted")
.Sum(x => x.Price);
But another problem will occur, that's because Sum method returns Nullable<Decimal>, while your method Prices2 returns decimal. Click to see docs
To solve this problem you can use the following code instead:
return db.Order
.Where(x => x.Client == term && x.Acceptance == "Accepted")
.Sum(x => x.Price) ?? 0;
That will return the value returned by Sum or 0 if the returned value is null.

Linq remove where if the value is null

That My Linq query
var result = db.APPLICATIONS
.Where(a => Statuses.Contains(a.STATUS_ID))
.Where(a => a.TrackingNo == TrackingNo)
Statuses is a int list and TrackingNo is a nullable int (int?).
Problem:
If the TrackingNo is null then i dont want to run this clause or just skip this condition.
LINQ queries can be built in multiple steps:
var result = db.APPLICATIONS
.Where(a => Statuses.Contains(a.STATUS_ID));
if (TrackingNo != null)
{
result = result.Where(a => a.TrackingNo == TrackingNo);
}
Note that if you have a Select (a projection), you probably must build the query in multiple steps in multiple variables:
var result2 = result.Select(a => new { a.STATUS_ID });
with the result2 "built" after the if.
You can check a nullable int by using its "HasValue" property.
var result = db.APPLICATIONS
.Where(a => Statuses.Contains(a.STATUS_ID))
.Where(a => a.HasValue && (a.TrackingNo == TrackingNo))
This will cause it to evaluate the "HasValue" prior to checking the value itself. If HasValue return false, then it will never evaluate the rest of the expression (and thus not cause NullReferenceException).
If it is of type "int?", then this will work.
Just add && condition and check null. And you can use 1 where condiiton here why second where.Pls try this:
var result = db.APPLICATIONS
.Where(a => Statuses.Contains(a.STATUS_ID)
&& a.TrackingNo!=null
&& a.TrackingNo == TrackingNo)
You should first check the values of the filtering parameters before trying to add more stuff to the store expression. This would only apply the Statuses and TrackingNo filtering if the nullable TrackingNo has a value. Otherwise it will return all APPLICATIONS as IQueryable.
var result = db.APPLICATIONS.AsQueryable();
if (TrackingNo.HasValue)
{
result = result.Where(a => Statuses.Contains(a.STATUS_ID) && a.TrackingNo == TrackingNo);
}
return result;
Alternatively, this would check if you have any statuses to apply and the tracking separatedly.
var result = db.APPLICATIONS.AsQueryable();
if (Statuses != null && Statuses.Count() > 0)
{
result = result.Where(a => Statuses.Contains(a.STATUS_ID));
}
if (TrackingNo.HasValue)
{
result = result.Where(a => a.TrackingNo == TrackingNo);
}
return result;
Or third option, as it is unclear what you really wanted. This would apply the statuses filtering always and tracking only if it is available
var result = db.APPLICATIONS.Where(a => Statuses.Contains(a.STATUS_ID));
if (TrackingNo.HasValue)
{
result = result.Where(a => a.TrackingNo == TrackingNo);
}
return result;

How to return empty string if an object is null?

Here is a snippet of my code:
var link = socials.Where(p => p.type == Facebook).FirstOrDefault().URL;
the problem is that there aren't any social object in the list, FirstOrDefault() return null, and .URL trigger an exception.
How can I avoid this in "one" line with LINQ? Thus, if null return empty "" (or custom even better) string, else .URL?
You can use DefaultIfEmpty with an argument to specify the fallback value:
var link = socials
.Where(p => p.type == Facebook)
.Select(p => p.Url)
.DefaultIfEmpty("")
.First();
FirstOrDefault is not necessary anymore, it is safe to use First with DefaultIfEmpty.
Another option is to use null coalesce operator
var link = (socials
.Where(p => p.type == Facebook)
.Select(p => p.Url)
.FirstOrDefault()) ?? string.empty;
I understood that string.empty is preferred over "" but that may not be the case - see comment below.
UPDATE
In C# 6 there is a null conditional operator (also known as the "Elvis" operator):
var link = socials
.Where(p => p.type == Facebook)
.Select(p => p.Url)
.FirstOrDefault()?.URL ?? string.empty;
A simple example:
stringbuilder sb = null;
// do work
string s = sb?.ToString() ?? "no values found";
Using C# 6 you can use a null-conditional operator (?.) to return the URL if the object returned from the LINQ statement isn't null, i.e. if a value was found, or null otherwsie.
var link = socials.Where(p => p.type == Facebook).FirstOrDefault()?.URL;
If you then want to change a null value to an empty string or a custom string then use the null-coalescing operator (??).
var link = socials.Where(p => p.type == Facebook).FirstOrDefault()?.URL ?? "No URL";
It should be noted that this won't make any distinction between whether an object wasn't found or an object was found but had a null URL value.

Linq result if null then zero

How do I write something like this:
int result = database
.Where(x => x.Name == "Criteria")
.Sum(x => x.Count)) ?? 0;
Where it will return the sum value unless linq does not find anything in which case it will return 0.
EDIT: The field is not null-able.
EDIT 2: I am using Entity Framework.
You were very close with your original query. You only needed to cast your Count variable:
int result = database
.Where(x => x.Name == "Criteria")
.Sum(x => (int?)x.Count) ?? 0;
Doing it this way would be a little more efficient and elegant than wrapping it in a Try/Catch.
I suspect you are using Entity Framework. If you were just using Linq-to-Objects, the solutions everybody else have provided would have worked.
This should work fine (no need for ?? 0):
var result = database
.Where(x => x.Name == "Criteria")
.Sum(x => x.Count))
Unless you want to check if x itself is null or not:
var result = database
.Where(x => x != null)
.Where(x => x.Name == "Criteria")
.Sum(x => x.Count))
You can just write:
int result = database
.Where(x => x.Name == "Criteria")
.Sum(x => x.Count));
The Enumerable.Sum method already returns zero on no results. From the documentation:
returns zero if source contains no elements.
This should work just fine:
var result = database.Where(x => x.Name == "Criteria").Sum(x => x.Count));
If no elements are returned by the Where function then the Sum function will return 0.
All of the Linq functions that return an IEnumerable<T> will return an empty collection instead of null.
Use the Aggregate extension method where 0 is a seed value
int sum = database.Where(x=>x.Name == "Criteria")
.Aggregate(0, (total, next) => total +=next);
I did it in a way that no one is going to like but garrantee to work 100% of the time, behold!
int result = 0;
try{
result = database
.Where(x => x.Name == "Criteria")
.Sum(x => x.Count));
} catch (Exception e){ }

Order by child record value(s) that can be empty

I've tried some combinations but I just don't understand how to do the following:
Lets say I have tables Requests and RequestActivities. I need to get all request sorted by RequestActivity.TimeOfCreation in descending order but RequestActivity may be null.
List<DA.GeneralRequest> ongoingGeneralRequests = db.GeneralRequests
.Where(t => t.GeneralRequestStatusID != 3 && (t.SupervisorID == currentUserId || t.CreatorID == currentUserId || t.AssignedUsers.Any(au => au.UserID == currentUserId)))
.OrderByDescending(x => x.GeneralRequestActivities.OrderBy(ga => ga.GeneralRequestActivityDate).Last().GeneralRequestActivityDate) //gives exeption
.ThenBy(a => a.Deadline).ToList();
I'm not really familiar with LINQ-To-SQL but doesn't work MAX in this case?
.OrderByDescending(x => x.GeneralRequestActivities
.Max(ga => ga.GeneralRequestActivityDate))
.ThenBy(a => a.Deadline)
.ToList();
You need to first cache the ordering value, and then order by the date if it is not null, else by some default date you want:
List<DA.GeneralRequest> ongoingGeneralRequests = db.GeneralRequests
.Where(t => t.GeneralRequestStatusID != 3 && (t.SupervisorID == currentUserId || t.CreatorID == currentUserId || t.AssignedUsers.Any(au => au.UserID == currentUserId)))
.Select(x => new {
Value = x,
OrderByValue = x.GeneralRequestActivities
.OrderBy(ga => ga.GeneralRequestActivityDate)
.LastOrDefault()) // cache value
.OrderByDescending(x => x.OrderByValue != null ?
OrderByValue.GeneralRequestActivityDate
: some default value)
.ThenBy(a => a.Value.Deadline)
.Select(a => a.Value)
.ToList();
Note that you can't use Last() extension method on empty IEnumerable. This is why you get the exception:
InvalidOperationException : The source sequence is empty.
In this line:
x.GeneralRequestActivities.OrderBy(ga => ga.GeneralRequestActivityDate).Last()
x.GeneralRequestActivities is empty, so calling Last() on it result on the exception.
Instead, use the LastOrDefault() extension method, which return null if the IEnumerable is empty.
Return Value Type: TSource default (TSource) if the source sequence is
empty; otherwise, the last element in the IEnumerable.

Categories

Resources