0

I am having issues with a Linq query when it runs I receive the error Object reference not set to an instance of an object.

var RestaurantName = (from r in objCtx.Restaurants
                      where r.id == item.restaurantid
                      select r).SingleOrDefault<Restaurant>().Name;

I then changed the query to

var RestaurantName = (from r in objCtx.Restaurants
                      where r.id == item.restaurantid
                      select r).Single<Restaurant>().Name;

But I received the error Sequence contains no elements. I checked the variable and it was returning a restaurant name. But I don't understand why I am receiving these errors.

John Saunders
  • 157,405
  • 24
  • 229
  • 388
Dolaps
  • 269
  • 2
  • 8
  • 24
  • 8
    `Sequence contains no elements` means there is no items in the query results. that's why `SingleOrDefault()` is returning `null` and you get a NullReferenceException. Check your query criteria. – Federico Berasategui Mar 07 '14 at 19:50
  • Have you tried writing thw query like this: var RestaurantName = (from r in objCtx.Restaurants where r.id == item.restaurantid select r.Name).SingleOrDefault(); – TheGeekYouNeed Mar 07 '14 at 19:52
  • Almost all cases of `NullReferenceException` are the same. Please see "[What is a NullReferenceException in .NET?](http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-in-net)" for some hints. – John Saunders Mar 07 '14 at 19:59

5 Answers5

4

The problem is that your linq query returns an empty collection:

from r in objCtx.Restaurants
where r.id == item.restaurantid
select r

When you call SingleOrDefaultin your first example, it returns null (ie the default value). You receive an object reference not set ...because you're trying to invoke the Name property on a null reference.

In your second example you call Single. When you do that on a list with 0 or +1 elements, an exception will be thrown. (as you are experiencing).

The solution is to either make sure that you always retrieve a single instance, or to do a check before you access any properties on that object

Kenneth
  • 26,557
  • 4
  • 52
  • 79
2

As others have said, your result set is empty. This will cause Single to fail (this is documented), and it will cause SingleOrDefault to return the default value for the given type (null in the case of a class).

In addition to the solutions presented in other answers (using null guards), here's another using more LINQ:

var RestaurantName = (from r in objCtx.Restaurants
                      where r.id == item.restaurantid
                      select r).DefaultIfEmpty(new Restaurant() { Name="None" })
                               .SingleOrDefault().Name;

DefaultIfEmpty will change the "default" value returned by SingleOrDefault from null to the supplied value. This way you can safely access the Name property. Depending on exactly how your Restaurant class is built, you may want to create the default value differently. You should be able to supply a default of something like new { Name = "None" }, as well, creating an anonymous object, but that's up to you.

Brian S
  • 4,612
  • 4
  • 24
  • 42
0

The problem is that there are not items in the collection that fulfill the condition. SingleOrDefault returns null (for reference types), so that in the frst version you receive a NullReferenceException. Single throws an exception if there are no elements that are returned, that's why the second approach fails.

You need to check whether there are any results:

var restaurant = (from r in objCtx.Restaurants
                  where r.id == item.restaurantid
                  select r).SingleOrDefault<Restaurant>();
string restaurantName;
if (restaurant != null)
    restaurantName = restaurant.Name;
else
    restaurantName = string.Empty;
Markus
  • 15,389
  • 3
  • 25
  • 47
0

If, as you say, your second code sample (the one using Single) return no elements, then the first one (the one using SingleOrDefault) returned null. And you can't get the .Name property off of null.

I think you need to verify your query. Look at the data directly or perhaps even just loop through the data and see what the output is:

var restaurants = from r in objCtx.Restaurants
                  where r.id == item.restaurantid
                  select r;

foreach (var restaurant in restaurants)
{
    string name = restaurant.Name;
}

I'm guessing that the loop will never execute because its empty and you need to figure out what's wrong with your query.

If you need to handle the scenario where it might return no elements, then you just need an if check:

var restaurant = (from r in objCtx.Restaurants
                  where r.id == item.restaurantid
                  select r).SingleOrDefault<Restaurant>();

string restaurantName;
if (restaurant == null)
    restaurantName = string.Empty;
else
    restaurantName = restaurant.Name;
Tim
  • 14,433
  • 1
  • 39
  • 67
0

Single will through an exception if there are no items in the sequence.

Try:

var RestaurantName = ((from r in objCtx.Restaurants
                          where r.id == item.restaurantid
                          select r).Any()) ? (from r in objCtx.Restaurants
                          where r.id == item.restaurantid
                          select r).SingleOrDefault<Restaurant>().Name : string.empty;
Maess
  • 4,032
  • 18
  • 29