Object property suddenly becomes null when queried with a linq statement - c#

I have the following linq query:
private List<Port> DoCountriesSearch(string search)
{
return Countries.Where(x => x.CountrySearch.ToLower().Contains(search.ToLower())).ToList();
}
I have an object called Countries which is a list of Port objects with various properties. Each Port object contains a property called CountrySearch which you can see here:
But as soon as I try to run the linq query on Countries, suddenly the CountrySearch property is null which throws a null reference exception:
I've never had this issue with linq before. What am I missing?

Your list has a lot of entries. In some entries CountrySearch is not null, in others it is null. There is no magic happening with LINQ here.
You can fix this with a Null-conditional operator
private List<Port> DoCountriesSearch(string search)
{
return Countries.Where(
x => x.CountrySearch?.Contains(
search,
StringComparions.CurrentCultureIgnoreCase) == true
).ToList();
}
Note that == true is required here because we have to cope with null values.
See also:
Best way to check for nullable bool in a condition expression.
StringComparison Enum for possible values.

The issue was entirely my fault. I had a buried method that was appending Port objects to the bottom of the list that did not come from the database, therefore the CountrySearch fields for those items were indeed null.

Related

What is the logical difference between using Single and SingleOrDefault? [duplicate]

This question already has answers here:
Should I use Single() or SingleOrDefault() if there is a chance that the element won't be found?
(9 answers)
Closed 5 years ago.
I am not sure where shall I use Single and where shall I use SingleOrDefault. I understood the definition for both.
Single:
It will always return one row.
If no row found I will get an exception.
If multiple rows found I will get an exception.
SingleOrDefault:
It will always return one row, if not found then default value is returned (What is the meaning of this DEFAULT VALUE").
If multiple rows then exception.
Question 1: What is the meaning of "It will return default value"
Question 2: When to use Single and when to use SingleOrDefault.
I have a delete function where I have below code:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(int resumeId)
{
var r = _context
.Resumes
.Where(c => c.ResumeId == resumeId).SingleOrDefault();
_context.Resumes.Remove(r);
_context.SaveChanges();
return RedirectToAction("ResumeCenter");
}
I just blindly put SingleOrDefault everywhere (where I ATMOST expect one value), Please tell me a real world scenario when I should use "Single" and where I should use "SingleOrDefault".
As you said -
Single() will raise an exception if no row found.
SingleOrDefault() will instead return the default value (null for reference types, 0 for ints, \0 for chars etc`).
Use Single() in one of two cases:
When not getting a row is something that should not happen, and if it does, it means something is wrong.
When you are dealing with value types (ints, chars, etc'), and the default value might be a valid value in your values system (for instance, if you are getting 0 for an int but can't tell if it's because you got no row back or it's a valid value.
Use SingleOrDefault() for any other case.
If the row is not found, you'll need to compare the value you get to it's default value.
For further reading, here is a link to Microsoft page on the default value expression.
It's almost (but not quite) a question of style. Which do you prefer?
Single:
try
{
var x = someEnumerable.Single();
}
catch (InvalidOperationException)
{
//Did not contain exactly one record
}
SingleOrDefault:
var y = someEnumerable.SingleOrDefault();
if (y == null)
{
//Did not contain exactly one record
}
The exception-based approach is a little more coding, but it is nice because exceptions can be allowed to bubble up. That being said, I usually use the XXXOrDefault variants to avoid stack unwind, which can be poor for performance. As a rule you should avoid throwing exceptions when behaviors are expected.
P.S. The "default" for any type can be obtained by using the keyword default(type). For integers it is zero, for dates it is MinValue, for reference types it is null, etc.
P.P.S. In your example I would use Single and allow an exception to be thrown if the row is missing or there is more than one. Otherwise you may end up passing null to the subsequent Remove method. While that would fail too, it'd fail a line later than it ought to, resulting in a deceptive stack trace and making troubleshooting a little trickier.
OTOH, with small changes, you could make either one work:
public ActionResult Delete(int resumeId)
{
var r = _context
.Resumes
.Where(c => c.ResumeId == resumeId).SingleOrDefault();
if (r == null)
{
return RedirectToAction("ErrorPage");
}
else
{
_context.Resumes.Remove(r);
_context.SaveChanges();
return RedirectToAction("ResumeCenter");
}
}
Or
public ActionResult Delete(int resumeId)
{
var r = _context
.Resumes
.Where(c => c.ResumeId == resumeId).Single(); //Error will bounce up to Application_Error or other global handler
_context.Resumes.Remove(r);
_context.SaveChanges();
return RedirectToAction("ResumeCenter");
}
as the function name suggest you when you say
list.single();
then that means
"I want the single record from the list" and hence you get the single
record (the 1st one)"
and when yo say
list.SingleOrDefault();
then that means
"I wan the single record and if the record dosen't exist the i would
like to have the default value of the object"
its your approch completely you can also go for
FirstOrDefault();
just like single or default
Single :
It returns a single specific element from a collection of elements if element match found. An exception is thrown, if none or more than one match found for that element in the collection.
SingleOrDefault:
It returns a single specific element from a collection of elements if element match found. An exception is thrown, if more than one match found for that element in the collection. A default value is returned, if no match is found for that element in the collection.
When you know that there has to be a value for some thing in the database, use Single() because you would want to get an exception if the "very expected value" in the database does not exist. Data like EmployeeName for a particular employee code.
Use SingleOrDefault() when you know employee is a temporary employee and his department may not show up in the main database. But if value for department exists, it should be only one value. He will not be working for multiple departments at once.
http://www.c-sharpcorner.com/blogs/singleordefault-vs-firstordefault-in-linq-query1
Single() - Atleast one value is expected in data store, and you would want it. You want to know if there is no value or multiple values. In that case, you get an exception and check.
SingleOrDefault() - Give one record with the default value if it does not exist. It does not matter whether on not anything is available for the record. But it should not be multiple records.

Benefits between .ToList().First() verse .Single for IQueryable in c#

So I am running a linq query on a NOSQL database that should return only a single object if one exists with that Id or nothing if nothing exists, but it is possible there are two objects with the same id in the database (if someone else messed up.) Currently I have it implemented as follows:
(from c in [IQueryableThing] where c.Id.Equals(id)).ToList().First()
I have also considered the alternative
(from c in [IQueryableThing] where c.Id.Equals(id)).Single()
I assume .Single() is faster but I am concerned that neither of these handles the case that there is no object with the correct id in the database. I don't care if there is more than one returned. I only want one of them. Eventually I will implement something to return the most recently modified.
Basically my question is what is the best way to solve this problem of converting a queryable to a single instance in a way that handles the cases where there is no object with the correct id and there is more than one object with the correct id.
It sounds like you just want to call FirstOrDefault(), which does exactly what the name implies.
Default means null.
You should not call ToList(); that will needlessly download all of the results from the database.
Using IQueryable.Single is more efficient:
Calling ToList enumerates the entire result set and stores each item in an single, contiguous array in memory. The First then just takes the first item from the array.
Calling IQueryable.Single evaluates only the first item in the list, and if no items are returned, throws an exception. It then checks to see if there are any more items in the result set, and throws an exception if there are any.
If you'd like to handle the case where no items exist in the set which match your criteria, but don't care if there are more than one, I'd strongly recommend using FirstOrDefault instead:
var result = (from c in [IQueryableThing] where c.Id.Equals(id)).FirstOrDefault();
if (result == null)
{
// no items found
}
This will translate to a TOP 1 in SQL, and simply return the first item in the result set, or if the result set is empty, it will simply return null (or the default value if you're dealing with structs).
The .ToList() shouldn't make a difference, it will just enumerate the queryable into an in-memory list. For your situation, you have a number of options. The two you've shown behave very differently:
.First() - This will return the first element in the enumeration, or throw an exception if there are none.
.Single() - This will return the only element in the enumeration, or throw an exception if there are none or if there are more than one.
.FirstOrDefault() - This will return the first element in the enumeration, or a default value (which is null for reference types) if there are none.
.SingleOrDefault() - This will return the only element in the enumeration, or a default value (which is null for reference types) if there are none, or throw an exception if there are more than one.
It sounds like you want to use .FirstOrDefault(). Check if the result is null. If it is, there were no matching elements. If it isn't, you have the first matching element.
I believe you are looking for Enumerable.FirstOrDefault
Returns the first element of a sequence, or a default value if the
sequence contains no elements.
You should use .FirstOrDefault(c => c.ID.Equals(id));
It will return default if nothing is found (default is null for classes) or the first one it finds.
In case you are sure that ONE and only ONE item exists and you will want to use Single()
If case you are not sure how many items will be returned used First() Or FirstOrDefault().
The difference is that Single() will throw an exception if more than one item exists. Very usefull if you want to trap insertion errors etc on a database without unique constraints.

C# LINQ nullable .Where inline null check

I am attempting to do the following
List<JobPhase> jobPhases = new JobPhaseDao().findAll();
jobPhases.Remove(jobPhases.Where(m => m.Name.Contains("Pre")).First());
Is there an elegant way to do an inline null check here such that if the list find any matches I can remove nothing?
Thanks
List.Remove appears to already support this behavior: pass a null as the parameter, and it should remove nothing.
To avoid an exception when your .Where call returns no matches, use FirstOrDefault() instead of First().
Note that if you expect only one item to match the Where predicate, you should use SingleOrDefault rather than First.
That said, it's not entirely clear what you're trying to do: if you have multiple JobPhases that contain "Pre" in the name, you are somewhat-arbitrarily removing one of them from the list. Are you instead trying to remove all matching JobPhases? If so, you should explore a different approach, such as using RemoveAll(). For example:
List<JobPhase> jobPhases = new JobPhaseDao().findAll();
jobPhases.RemoveAll(jobPhases.Where(m => m.Name.Contains("Pre")));
List<JobPhase> jobPhases = new JobPhaseDao().findAll()
.Where(m => !m.Name.Contains("Pre"));

LINQ Query Issue, Sequence contains no elements

I'm trying to update a single record in a table, but when I run .Firstordefault(), I get the error: "Object reference not set to an instance of an object.", and if use it with .First(), I get "Sequence contains no elements".
Using it another place, its working fine, but this time its causing errors.
Here's the code:
public class AllownceDetails
{
public int ta_id{get;set;}
public int tvrid{get;set;}
public DateTime ofDate{get;set;}
public string status{get;set;}
public string userid {get;set;}
}
//Update Method
public void Update(AllownceDetails Allowncedtl)
{
var ta = (from a in ce.tbl_tvrallownce
where a.tvrid == Allowncedtl.tvrid
//error: Sequence contains no elements
select a).SingleOrDefault();
ta.status = Allowncedtl.status;
//error:Object reference not set to an instance of an object
ce.SaveChanges();
}
The query must not be returning any data. Run a profiler on the SQL database to see the physical query being executed and try to execute it manually against the database to see what the data looks like. You probably have to adjust the query (or the data) to get the results you're looking for.
"Sequence contains no elements" is basically LINQ's way of telling you that you're trying to reference an element from a list that doesn't have anything. So calls to things like .First() or .Single() can't find anything, hence the error.
When you change the calls to something like .FirstOrDefault() or .SingleOrDefault() then it will go with "default" value for that type, and for reference types the default is null. So if you set something to null and then try to call a method on it, you'll get object reference not set to an instance of an object.
The Single method throws this exception when there are no elements in list(query) or there are multiple elements.
The SingleOrDefault method throws an exception when there are multiple elements in the list. Returns null when there are no elements.
The FirstOrDefault method return the first item in the list or null. There are no exceptions.
Use it and the check the reference for null
if (ta != null )
{
ta.status = Allowncedtl.status;
ce.SaveChanges()
}
The source will always be an object, so no worries about it in your case.
All that means is that your query isn't matching anything. Presumably Allowncedtl.tvrid is an ID which doesn't match anything in the database. You shouldn't assume that SingleOrDefault will return a non-null value. Only use SingleOrDefault when you're expecting that there may be no values - and cope with that. If a failure to find a value indicates a bug, you should use Single (or perhaps First) instead.
We can't tell anything about what the underlying cause of your error is - you should log which ID you were looking for, work out why you were looking for that, and then check it in the database.

LINQ filter by type on list from dictionary value

Think this is a very basic question, but it's my first LINQ query and I'm completely stuck:
I have a dictionary with string key and list value (see definition below) and want to pull out elements of a list of a particular type having selected the list by the dictionary key.
IDictionary<string, IList<MyBaseType>> dataItemMap;
Where MySubType extends MyBaseType.
My dodgy query is:
string identCode = "foo";
IEnumerable<MySubType> query =
from entry in dataItemMap
where entry.Key == identCode
select entry.Value.OfType<MySubType>();
And the error message (from LinqPad):
Cannot implicitly convert type
'System.Collections.Generic.IEnumerable<System.Collections.Generic.IEnumerable<MySubType>>'
to 'System.Collections.Generic.IEnumerable<MySubType>'.
An explicit conversion exists (are you missing a cast?)
The problem is clearly in the entry.Value.OfType<> but how can I specify the lists elements? I'm looking for something like entry.Value.Items.OfType<> ?
thanks.
I think you want something like this:
IEnumberable<MySubType> query = dataItemMap[identCode].OfType<MySubType>();
This will get the list with the given key, and then filter it to return only MySubType elements.
EDIT: I've been focusing on why the existing solution didn't work (and the general problem of "I've got a list of values for each element, and I want to flatten it") rather than taking a step back. As Andy's answer shows, you should almost certainly use the fact that it's a dictionary - turning it from an O(n) operation to O(1) :)
Two caveats:
Your current code will always perform an ordinal, culture-insensitive comparison with identCode and the dictionary keys; using the dictionary lookup will use whatever comparer it was constructed with.
Your current code will return an empty sequence if identCode isn't found in the dictionary; the dictionary indexer will throw an exception. You can use TryGetValue if you want to avoid that.
Note that if you know that all the elements in the last you're picking are actually of the right type, it would probably be better to use Cast than OfType:
var query = dataItemMap[identCode].Cast<MySubType>();
I generally prefer Cast to OfType when both would work, as it means that if my assumptions about the data in the sequence prove incorrect, I find out about it with an exception rather than silently missing data.
Note that Cast will also return null elements, whereas OfType won't.
No, the problem isn't in using OfType<> - it's that you've ended up with a sequence of sequences, but you're trying to assign that to a single sequence.
Either change the return type, or use another from clause to flatten the results:
IEnumerable<MySubType> query = from entry in dataItemMap
where entry.Key == identCode
from value in entry.Value.OfType<MySubType>()
select value;
I'd be tempted to use the extension methods directly:
var query = dataItemMap.Where(e => e.Key == identCode)
.SelectMany(e => e.Value.OfType<MySubType>());

Categories

Resources