Reputation: 7261
Is there any reason why the Any
function in the following code could fail?
var orders = db.Order.Where(order => order.Item.Any());
foreach (var order in orders)
{
var first = order.Item.First(); // NullReferenceException thrown here: order.Item == null
}
Maybe I'm simply misunderstanding something here, but it seems to me order.Item
should never be null due to the earlier Any
statement.
Edit: if I make sure the expression is evaluated and not deferred by putting a ToList
there, I get another exception due to the order.Item
sequence having no items, which also baffles me:
var orders = db.Order.Where(order => order.Item.Any()).ToList();
foreach (var order in orders)
{
var first = order.Item.First(); // System.InvalidOperationException thrown here: order.Item.Count == 0
}
Upvotes: 2
Views: 566
Reputation: 30464
It is simpler than you think. According to the definition of Enumerable.Any the ArgumentNullException is thrown if source is null.
Your class Order has a property Order.Item. One of your orders has an Item with value null. Your code should be:
var orders = db.Order.Where(order => order.Item != null && order.Item.Any());
Upvotes: 0
Reputation: 726579
The expression that computes orders
is deferred, so when there are any null
s in db.Order
's Item
, you wouldn't find them until you are in the foreach
loop.
You can see what's going on by adding a ToList()
call:
var orders = db.Order.Where(order => order.Item.Any()).ToList();
Now the exception will be thrown before the loop.
You can fix this by adding an explicit null
check in the Where
condition, or by using the new ?.
syntax of C# 6:
var orders = db.Order.Where(order => order.Item != null && order.Item.Any());
or
var orders = db.Order.Where(order => order?.Item.Any());
The order.Item.Count == 0
error may be of the same nature: since the check for Any()
is done at the DB level, and the call for First()
happens at some later time, chances are that the item that was there for Any()
to succeed is gone by the time you call First()
.
You should be able to fix this by adding LoadWith
option for Item
.
Upvotes: 8
Reputation: 137148
This line:
var orders = db.Order.Where(order => order.Item.Any());
won't actually evaluate until it needs to, so appears to fail later on.
If you replace the line with:
var orders = db.Order.Where(order => order.Item.Any()).ToList();
you'll see the failure immediately as the query is evaluated when the list is generated.
Replace the line with:
var orders = db.Order.Where(order => order.Item != null && order.Item.Any());
and it should work OK
Upvotes: 4