LINQ Lambda only select if exists - c#

I am using NHibernate which is abstracted away using Respositories and services. We are not allowed to Lazy Load properties, so they have to be selected in the query.
My issue is that I am trying to get the most recent response number from the Answers table, but in many cases the object might not exist, so I am stuck with getting Null Reference exceptions, or "Code should be unreachable" exceptions.
Here is what i'm doing with the approprtiate sections commented.
.
var leaders =
_storeService.GetAll()
.Where( p => p.Id.Equals(storeId) && p.Employees.Any() )
.SelectMany(p => p.Employees)
.Select(emp => new
{
LeaderId = emp.Id,
LeaderFirstName = emp.FirstName,
LeaderLastName = emp.LastName,
Followers = emp.Followers
.Select(followers => new
{
followers.FollowerEmployee.Id,
followers.FollowerEmployee.FirstName,
followers.FollowerEmployee.LastName,
DepartmentName = followers.FollowerEmployee.Department.Name,
//Problem Area
AssessmentResponse = followers.FollowerEmployee
.Answers
.First( a => a.Answer.Question.IsPrimary )
.Answer
.Number
//Null Reference Exception
} )
} ).ToList();
I've probably tried 15 iterations of this, not always using .First but sometimes .Single
I don't have access to the repository pattern or any of the NHibernate queries. Is there a way to avoid this null reference exception with LINQ? I can't lazy load, so it's a bit of an issue.

In EF/Linq-2-Sql, this can be made to work by casting to a nullable value since the underlying SQL does null-coalescing:
AssessmentResponse = (int?)followers.FollowerEmployee.Answers
.First(a => a.Answer.Question.IsPrimary).Answer.Number
I'm not sure what the behavior would be in NHibernate but it's worth a try. If the Number property is already nullable, you could try coalescing it:
AssessmentResponse = (int?)followers.FollowerEmployee.Answers
.First(a => a.Answer.Question.IsPrimary).Answer.Number ?? some default value
Finally, you could always do an explicity check:
AssessmentResponse = followers.FollowerEmployee.Answers.Any(a => a.Answer.Question.IsPrimary)
? followers.FollowerEmployee.Answers.First(a => a.Answer.Question.IsPrimary).Answer.Number ?? some default value
: null

Instead of this:
AssessmentResponse = followers.FollowerEmployee
.Answers
.First( a => a.Answer.Question.IsPrimary )
.Answer
.Number
//Null Reference Exception
Try this:
AssessmentResponse = followers.FollowerEmployee
.Where(a=>a.Answers != null && a.Answers
.Where(a=>a.Answer.Question.IsPrimary)
.Count > 0)
.Answers
.FirstOrDefault( a => a.Answer.Question.IsPrimary )
.Answer
.Number
//Null Reference Exception

Related

C# Query - Non Static Method Requires a Target

i am getting an error that says 'Non Static Method requires a target'
Here is the code that is causing me the error, could anyone possible shed some light on this?
//TODO: Error, Non static method requires a target.
var orderItem =
_context.PurchaseOrderItems.FirstOrDefault(
p => p.JobReference == item.JobReference && p.ItemNumber == item.ItemNumber);
return _context.DeliverySchedules.Include(d => d.PurchaseOrderItem)
.Where(d => d.PurchaseOrderItem.Id == orderItem.Id)
.ToList();
The FirstOrDefault method may return null value if no query results returned there:
var orderItem = _context.PurchaseOrderItems.FirstOrDefault(
p => p.JobReference == item.JobReference && p.ItemNumber == item.ItemNumber);
Since orderItem.Id throws NullReferenceException when orderItem is null, it will propagate to LINQ throwing TargetException as mentioned in question (see this post and this post for more info).
Hence, you need to check presence of null value from orderItem by modifying second LINQ query to this one:
return _context.DeliverySchedules.Include(d => d.PurchaseOrderItem)
.Where(d => (orderItem != null && d.PurchaseOrderItem.Id == orderItem.Id))
.ToList();
NB: Null checking must takes place before retrieving property Id of orderItem to prevent NullReferenceException.
As an alternative, if condition to check against null value may be used without modifying second query:
if (orderItem != null)
{
return _context.DeliverySchedules.Include(d => d.PurchaseOrderItem)
.Where(d => d.PurchaseOrderItem.Id == orderItem.Id)
.ToList();
}
Change the FirstOrDefault to Single because in the next line you will get to its properties and you dont want a NullReferenceException

Handling empty collections in Entity Framework

I fill up a List in Entity Framework;
List<StockProperties> props = db.StockProperties
.Where(prop => prop.Stok_ID == stok.ID)
.ToList();
The problem here is if my query is null, it returns a
Non-static method requires a target.
error which is obvious since EF does that with empty sequences.My question is what is the most reasonable way to handle these null queries?I want my list to be empty if my query returns null sequences.
This:
List<StockProperties> props = db.StockProperties
.Where(prop => false)
Is returning a System.Linq.Enumerable.WhereListIterator<StockProperties> with 0 reccords it will never be null.
Your problem may be with prop => prop.Stok_ID == stok.ID
Do stok is declared?
Check here
You can supply a fall back option for null
var props =
db.StockProperties.Where(prop => prop.Stok_ID == stok.ID)
?? Enumerable.Empty<StockProperties>();
or
var props =
db.StockProperties.Where(prop => prop.Stok_ID == stok.ID).ToList()
?? new List<StockProperties>();

Linq error: The cast to value type 'Int32' failed because the materialized value is null

... But it's not null.
FYI - Many threads exist on this error, but none that I've seen using an anonymous type.
I'm Getting an odd InvalidOperationException in a Linq query.
message: "The cast to value type 'Int32' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type."
The confusing thing is that it's erroring when creating an anonymous type:
var workstepid = 484,449;
var wsData = ion.xWorkSteps
.Where(w => w.WorkStepId == workstepId)
.Select(w => new
{
w.WorkStepId,
w.ServiceId,
w.Service.TitleId,
w.Service.Title.OrderId,
w.Service.Title.AltTitleId
}).SingleOrDefault();
In LinqPad this particular query runs just fine and the workstepId used returns an integer value for each property of the anonymous type. So why a casting error when there is no null value for any property!?
FYI, the last property AltTitleId is a nullable int, and the other properties are ints.
Also, this code was written weeks ago and I didn't get this error until today. Is something funky w/ my EF?
Edit: SOLVED
We use soft-delete in our db's, setting deleted records to Acive=0.
It turns out that there is a property set in EF on the edmx tables filtering out inactive records (filter for Active=1). Naturally, this wouldn't effect Linqpad which gives me the expected result, but since this was an older record I was testing, the title record (Service.Title) had been marked Active=0 and was therefore returning null.
Thanks to everyone for the help.
var workstepid = 484,449;
var wsData = ion.xWorkSteps
.Where(w => w.WorkStepId == workstepId)
.Select(w => new
{
w.WorkStepId.Value,
w.ServiceId.Value,
w.Service.TitleId.Value,
w.Service.Title.OrderId.Value,
w.Service.Title.AltTitleId.Value
}).SingleOrDefault();
Hi you need to add .Value in your int data type to accept null value. hope this helps
If w.WorkStepId is nullable, try setting your variable as...
int? workstepid = 484449;
I suppose, the problem is in your SingleOrDefault().
I suppose that you get 0 records:
var workstepid = 484,449;
var len = ion.xWorkSteps
.Where(w => w.WorkStepId == workstepId)
.Length();
And then the anonymouse type must be replace by Default (this is what SingleOrDefault do), but there is no default for your anonymous type.
Try to change it to:
var wsData = ion.xWorkSteps
.Where(w => w.WorkStepId == workstepId)
.Select(w => new
{
w.WorkStepId,
w.ServiceId,
w.Service.TitleId,
w.Service.Title.OrderId,
w.Service.Title.AltTitleId
})
.Take(1)
.ToArray();
May be there are no Service/Title/Order id somewhere, but if it declared as int anonymous type expect int (not nullable), but from database it returns null.
Try to rewrite as :
var workstepid = 484,449;
var wsData = ion.xWorkSteps
.Where(w => w.WorkStepId == workstepId)
.Select(w => new
{
WorkStepId = (int?)w.WorkStepId,
ServiceId = (int?)w.ServiceId,
TitleId = (int?)w.Service.TitleId,
OrderId = (int?)w.Service.Title.OrderId,
w.Service.Title.AltTitleId
}).SingleOrDefault();

LINQ to SQL lambda where [nullable object must have a value error]

I'm getting the error
[nullable object must have a value]
And it's point at the following part of the code
.Min(x => x.Time)
Here's the whole function.
public DateTime GetFirstRecord(long userId)
{
DateTime firstRecordDate;
using (DeviceExerciseDataDataContext context = new DeviceExerciseDataDataContext())
{
firstRecordDate = (DateTime)context.Datas.Where(x => x.UserID.Equals(userId)).Min(x => x.Time);
}
return firstRecordDate;
}
Also, how can I debug this functions lambda? When I hover over the x's, It shows no value. When when I try to print in the immediate window, it says "the name 'x' does not exist in the current context"
Edit:
So I've updated my code to this:
public DateTime? GetFirstRecord(long userId)
{
DateTime? firstRecordDate;
firstRecordDate = DateTime.Now;
using (DeviceExerciseDataDataContext context = new DeviceExerciseDataDataContext())
{
var test = context.Datas.Where(x => x.UserID.Equals(userId));
if (test != null)
firstRecordDate = (DateTime)test.Min(x => x.Time);
else
firstRecordDate = null;
}
return firstRecordDate;
}
But I'm still getting the save error.
In the DB, There are no null value's anywhere. Oh, and it doesn't go to the else, in the if/else block.
There is a good chance that context.Datas could be null or any of the Data's userId could be null or x.Time is null and you are trying to cast it as (DateTime) instead of (DateTime?).
You will have to add conditions to capture these null values in your assignment statement something like:
DateTime? datevalue = context.Datas == null
? null
: (DateTime?)context.Datas.Where(x => x.UserId != null && x.UserID.Equals(userId))
.Min(x => x.Time);
If it is possible for firstRecordDate to be null, the .Min isn't allowed.
Can you try this?
firstRecordDate = (DateTime)context.Datas.Where(x => x.UserID.Equals(userId));
if (firstRecordDate.Count() > 0) firstRecordDate = firstRecordDate.Min(x => x.Time);
if that works, then that's your problem. There are probably more elegant ways to deal with this but at least you will have a workaround to start with.
If you can be assured that at least one row has a valid time you could filter out the entries that have null as Time (or handle the case that DateTime.MaxValue is returned)
firstRecordDate = context.Datas.Where(x => x.UserID == userId)
.Select( x=> x.Time ?? DateTime.MaxValue)
.Min();
Try
(DateTime)context.Datas.Where(x => x.UserId != null && x.UserID.Equals(userId)).Min(x => x.Time)
The userID != null should evaluate first which will prevent nulls when you get to the Min. I haven't tested that but I think I remember doing stuff like it in the past.
The Min function is attempting to return the minimum value, and I've encountered this message before when no elements were being returned from the IQueryable - you need to check for the existance of elements before invoking, or declare firstRecordDate as a DateTime?.
Debugging lambda's is not supported in the watch window. If you want to debug it, I would suggest instead making it a long form lambda over multi line in order to debug
.Where(x =>
{
return x.ToString();
});
You would be able to debug the inner method code then.
You will get that error if context.Datas.Where(x => x.UserID.Equals(userId)) does not return any values.
If you use DateTime? instead of DateTime it will avoid this error by returning null.

Where Predicates in LINQ

How can I specify conditions in Where predicates in LINQ without getting null reference exceptions. For instance, if q is an IQueryable how can I do like:
Expression<Func<ProductEntity,bool>> predicate = p => !search.CategoryId.HasValue || (search.CategoryId.HasValue && search.CategoryId == p.CategoryId);
var q2 = q.Where(predicate);
Here search is an object that holds possible search conditions that may or may not be set like search.CategoryId might not be set but if it is I want to get the products that are set by that condition.
When I do this I get null reference exceptions.
You can use the null-coalescing operator ?? to replace a possible null value with a default value. The following sets tries to match the search.Category if it exists or simply creates an "always true" expression. This will be optimized by any good Linq query provider (e.g. LinqToSql).
Expression<Func<ProductEntity,bool>> predicate = p => (search.CategoryId ?? p.CategoryId) == p.CategoryId);
var q2 = q.Where(predicate);
Another possibility would be to dynamically compose a query predicate using PredicateBuilder. That's the way I do it for searches with a similar pattern as you use:
var predicate = PredicateBuilder.True<Order>();
if (search.OrderId))
{
predicate = predicate.And(a => SqlMethods.Like(a.OrderID, search.OderID);
}
// ...
var results = q.Where(predicate);
Let's dissect the line:
Expression<Func<ProductEntity,bool> predicate = p => !search.CategoryId.HasValue
|| (search.CategoryId.HasValue && search.CategoryId == p.CategoryId)
var q2 = q.Where(predicate);
So how many ways can we get null problems?
search (your "captured" variable) could be null
p could be null, meaning there is a null in the list
you've handled the case of search.CategoryId being null (Nullable<T>)
but maybe p.CategoryId (the category on a record in the list) is null (Nullable<T>) - however, I'm not sure that this would cause a NullReferenceException
q (the list / source) could be null
So: out of 5 options you've eliminated 1; look at the other 4? There is also the definite possibility that the issue is caused by something invisible not shown in the code; for example the get could be:
public int? CategoryId {
get {return innerObject.CategoryId;}
}
and innerObject could be null; if you eliminate the other 4 (pretty easy to do), look at at this one as a last resort.

Categories

Resources