I have an list of objects that contains another object in it.
List<MyClass> myClass = new List<MyClass>();
I want to do some linq like this
myClass.Where(x => x.MyOtherObject.Name = "Name").ToList();
Thing is sometimes "MyOtherObject" is null. How do I check for this?
Simple, just add an AND clause to check if it's not null:
myClass.Where(x => x.MyOtherObject != null && x.MyOtherObject.Name = "Name").ToList();
As of C# 6, you can also use a null conditional operator ?.:
myClass.Where(x => x.MyOtherObject?.Name == "Name").ToList();
This will essentially resolve the Name property to null if MyOtherObject is null, which will fail the comparison with "Name".
Try it online
You can just make your predicate check for null...
myClass.Where(x => (x.MyOtherObject == null) ? false : x.MyOtherObject.Name == "Name").ToList();
I would do something like this:
myClass.Where(x => x.MyOtherObject != null)
.Where(y => y.MyOtherObject.Name = "Name")
.ToList();
Related
I have an Expression that looks like this:
obj => obj.Child.Name
where Name is a string. What I want to do is get the value of Name. I can get it just fine by compiling the method and invoking it, however a NullReferenceException is thrown if Child is null. Is there a way to check if Child is null in this scenario?
With the current C# version 5.0 (or lower), you have to explicitly check for each property like:
if(obj != null && obj.Child != null)
{
//get Name property
}
With C# 6.0 you will be able to check it using Null conditional/propagation operator.
Console.WriteLine(obj?.Child?.Name);
obj => obj.Child == null ? null : obj.Child.Name
or using C# 6
obj => obj.Child?.Name
obj => obj.Child == null ? "" : obj.Child.Name;
You can filter them previously(with a Where), something like this:
var results = source.Where(obj => obj.Child != null).Select(obj => obj.Child.Name);
Like this, you will prevent those null reference errors.
I've got a method which can accept an optional int? value as a number of items to Take from a collection. I want to return all items if a null value is passed. Right now I have to duplicate my query to accomplish this
if(take == null)
{
x = db.WalkingDeadEps.Where(x => x.BicyclesCouldHaveSavedLives == true).ToList()
}
else
{
x = db.WalkingDeadEps.Where(x => x.BicyclesCouldHaveSavedLives == true).Take(take).ToList()
}
Is there a simpler way? Something like this?
.Take(take != null ? take : "all")
with Linq you have the option to store your query in variables. it will not be executed until you call ToList or equivalent methods on it.
var query = db.WalkingDeadEps.Where(x => x.BicyclesCouldHaveSavedLives == true);
x = take.HasValue ? query.Take(take.Value).ToList() : query.ToList();
Here is my code:
string displayName = Dictionary.FirstOrDefault(x => x.Value.ID == long.Parse(options.ID)).Value.DisplayName;
The code works fine if x.Value.ID matches options.ID. However, I get a NullReferenceException if it doesn't.
FirstOrDefault returns the default value of a type if no item matches the predicate. For reference types that is null. Thats the reason for the exception.
So you just have to check for null first:
string displayName = null;
var keyValue = Dictionary
.FirstOrDefault(x => x.Value.ID == long.Parse(options.ID));
if(keyValue != null)
{
displayName = keyValue.Value.DisplayName;
}
But what is the key of the dictionary if you are searching in the values? A Dictionary<tKey,TValue> is used to find a value by the key. Maybe you should refactor it.
Another option is to provide a default value with DefaultIfEmpty:
string displayName = Dictionary
.Where(kv => kv.Value.ID == long.Parse(options.ID))
.Select(kv => kv.Value.DisplayName) // not a problem even if no item matches
.DefaultIfEmpty("--Option unknown--") // or no argument -> null
.First(); // cannot cause an exception
You can use a combination of other LINQ methods to handle not matching condition:
var res = dictionary.Where(x => x.Value.ID == someID)
.Select(x => x.Value.DisplayName)
.DefaultIfEmpty("Unknown")
.First();
Simply use the question mark trick for null checks:
string displayName = Dictionary.FirstOrDefault(x => x.Value.ID == long.Parse(options.ID))?.Value.DisplayName ?? "DEFINE A DEFAULT DISPLAY NAME HERE";
That is because FirstOrDefaultcan return null causing your following .Value to cause the exception. You need to change it to something like:
var myThing = things.FirstOrDefault(t => t.Id == idToFind);
if(myThing == null)
return; // we failed to find what we wanted
var displayName = myThing.DisplayName;
To add to the solutions, here is a LINQ statement that might help
Utilities.DIMENSION_MemTbl.Where(a => a.DIMENSION_ID == format.ContentBrief.DimensionID).Select(a=>a.DIMENSION1).DefaultIfEmpty("").FirstOrDefault();
The result will be an empty string if the result of the query is a null..
This answer is for those of us who need a visual write up (like me :)
In the code screenshot below, a NullReferenceException will be thrown, the root cause is the ReferenceIdentification_02 property.
When debugging, we see that the orderLine.REF array, I am querying does not include a matching object whose ReferenceIdentificationQualifier_01 value == "RU", so at that point FirstOrDefault() return value is NULL
to prevent the NullReferenceException, I do a FirstOrDefault() on the orderLine.REF array first. If the returned value is not null then I retrieve the value.
i assume you are working with nullable datatypes, you can do something like this:
var t = things.Where(x => x!=null && x.Value.ID == long.Parse(options.ID)).FirstOrDefault();
var res = t == null ? "" : t.Value;
you can use with 'Where' statement with FirstOrDefault().
like this.
var modelItem = _dbcontext.ModelName.Where(n => n.NewsTagId == newsTag.Id).FirstOrDefault();
It returns first item if does not match query.
It is better practice to check the NULL after query.
if(modelItem == null)
{
return "Not Found."
}
else
{
// continue process
}
var x = new {
Name = "qwe",
Options = someList.Select(x=>x.KEY).Select(x =>
new {
Title: someOtherList.FirstOrDefault(y => y.KEY == x) != null ?
someOtherList.FirstOrDefault(y => y.KEY == x).Title :
null
}
)
}).ToList();
I'm making a serializeable list of objects. Please have a look on how i fetch the Title property for each option.
My problem is that I'm fetching more properties than the title, and the conditional operator feels quite excessive for each property.
Is there any "better" way of writing this?
A simple solution would be to use the following:
Title= someOtherList.Where(y => y.KEY == x).Select(x => x.Title).FirstOrDefault()
That is doing the following:
From someOtherList, return those elements with Key equal to x.
From those elements, select the Title.
Return the first title - or null if there are none.
Canonically, the approach most similar to the original code is to use a statement lambda.
Options = someList.Select(x=>x.KEY).Select(x =>
{
var other = someOtherList.FirstOrDefault(y => y.KEY == x);
return new {
Title = other == null ? null : other.Title
};
})
You can call a method instead:
Options = someList.Select(x=>x.KEY).Select(x => CreateObject(x, someOtherList));
public YourObject(or dynamic) CreateObject(YourObject x, List<SomeOtherObject> someOtherList)
{
var other = someOtherList.FirstOrDefault(y => y.KEY == x);
return new
{
Title = (other == null ? null : other.Title),
Foo = (other == null ? null : other.Foo),
...
}
}
Or accomplish the same with the let keyword in a Linq query expression as #DarinDimitrov displays.
When I
bool? isApproved = null;
db.Table.Where(item => item.IsApproved == isApproved).Count();
the last line value is 0. But when I
db.Table.Where(item => item.IsApproved == null).Count();
the value is correct.
I'm using SQLite, DbLinq and DbMetal.
I have seen it done like this:
db.Table.Where(
item => item.IsApproved.HasValue == isApproved.HasValue &&
(!item.IsApproved.HasValue || item.IsApproved.Value==isApproved.Value )
).Count();
Well, I had this problem before, I remember that the problem is in converting the LINQ query to a SQL statement.
The second expression has an equal in SQL that:
Where IsAproved is null
but the first expression does not because it is a comparision between a value in the database with a C# nullable variable.
To solve it, I would suggest to try:
db.Table.Where(item => isApproved != null ? item.IsApproved == isApproved.Value
: item.IsApproved == null).Count();
See this post
You should use
db.Table.Where(item => item.IsApproved.Equals(isApproved)).Count();
Then you should contact Microsoft and let them know how terrible this behavior is.
I don't know about the performance hit, but it works
bool? isApproved = null;
db.Table.Where(item => item.IsApproved == isApproved ||
!(item.IsApproved.HasValue || isApproved.HasValue))
.Count();
Try :
db.Table.Where(item => item.IsApproved == isApproved.Value).Count();