Reputation: 6300
I have a rather ugly service job that runs through a legacy database and compares it to our production database:
if (vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number) != null) {
var oldDbContractItem = vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number).First();
// check to see if there were changes
if (oldDbContractItem.DateStamp != vendorContractItem.Date_Stamp)
{
oldDbContractItem.Update(vendorContractItem);
}
}
I will get an error on var oldDbContratItem
, "Sequence contains no elements", yet I just did a != null check. This must be simple, what's going on?
Upvotes: 2
Views: 303
Reputation: 28897
After using a fix from the accepted answer, you can further debug the LINQ situation (if need be) by using the following steps. LINQ is an exciting technology but takes a while to wraps ones' head around it - a bit of a paradigm shift I would say. Eric's answer hit the nail on the head because he likely helped build the stuff!
Debugging Steps for LINQ
To deal with the issue of no results from the second statement change .First()
to .FirstOrDefault()
If nothing is found it will return the default value of the data type - if the data type is a class it will return a null value. Your second statement should then work with a null check too and without error.
Then you can debug your LINQ statement to find out why it's doing what it does.
if using LINQ to SQL, Intellisense in Visual Studio 2010 will show you the SQL generated when you hover over a query variable (not the result of a query). If you need the visualizer for VS 2008 it's here
Similarily if you're using LINQ to Entity Framework, you can get the generated SQL using the visualizer plugin here.
I always take the generated SQL from these tools, paste it directly into a query window and run it there. It will show you the empty set you're getting back and if that's a problem you can further debug it in this manner of visualizing the generated statements.
Upvotes: 0
Reputation: 660279
If I could teach people just one thing about LINQ it's this: the value of a query expression is an object that represents the query, not the results of the query. Fundamentally that's your problem; you're treating the query as its results. A query isn't a result any more than a restaurant is a club sandwich. A restaurant is a device which produces club sandwiches; a query is a device that produces results.
Upvotes: 17
Reputation: 283733
Don't run the query twice. It's inefficient and may introduce a race condition into your code. Also, your logic is much better supported by either using IEnumerator<T>
directly, or with a foreach
loop.
Use either:
var result = vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number).GetEnumerator();
if (result.MoveNext) {
var oldDbContractItem = result.Current;
// ...
}
or
foreach (var oldDbContractItem in vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number)) {
// ...
break;
}
Upvotes: 1
Reputation: 244908
There is difference between null
and an empty sequence (e.g. something similar to new List<T>()
). What you want to do is to use Any()
to check whether the sequence contains any elements, or rather replace First()
with FirstOrDefault()
, which returns null
if the sequence contains no element. (If you use that, make sure that null
is not a valid value that could be returned by First()
).
Upvotes: 0
Reputation: 54168
Where
can return a non-null value, but still resolve to a sequence containing no elements. In your failing statement you are using something else, which is Where().First()
. That will be null if the sequence from Where
is indeed empty.
Upvotes: 0
Reputation: 18815
Because your query returned a container, it just happened to be empty, the null check is on the return not what the return contains.
try this instead...
if (vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number).Any())
{
.....
}
Upvotes: 2
Reputation: 40150
This is the test against null
you are doing:
vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number) != null
That will always be true; That will always return at least an empty sequence... never a null
.
You might be meaning to test that its length is greater than 0?
There's an easier way, though, IMO. Call FirstOrDefault()
instead of First()
and leave out the pre-test completely. Then instead, test if the result of FirstOrDefault()
is null
.
var oldDbContractItem = vendorContract.Item
.Where(x => x.ItemNumber == contractItem.Item_Number).FirstOrDefault();
if(oldDbContractItem != null) //would be null if there are no items
{
// check to see if there were changes
if (oldDbContractItem.DateStamp != vendorContractItem.Date_Stamp)
{
oldDbContractItem.Update(vendorContractItem);
}
}
}
Upvotes: 7