ahnkle
ahnkle

Reputation: 477

How to detect no data returned in C# LINQ query

I am doing a repeated query below, with 'a' and 'b' incrementing ('b' increments to a limit, then reset and 'a' increments). There may be multiple row with given values of 'a' and 'b'.



    struct MyData {int mdA; int mydB; }
    ....

    int find_next_a(int a, int b)
    {
      var q = from p in db.pos
        where (p.a >= a && p.b > b) || (p.a > a && p.b > 0)
        orderby p.a, p.b
        select new MyData
        { 
          mdA = p.a, 
          mdB = p.b 
        };

      return q.First().mdA;   // ERROR: InvalidOperationException at end of data
    }

The query works until I reach the end of the table. Then I get the exception InvalidOperationException. I can't call q.Count() because I get the same exception.

How can I detect that q has no valid data in it?

[EDIT:] Thanks Jon Skeet (and Bojan Skrchevski, Bodrick), I post the solution to above.


    int find_next_a(int a, int b)
    {
      var q = from p in db.pos
        where (p.a >= a && p.b > b) || (p.a > a && p.b > 0)
        orderby p.a, p.b
        select new { p.a, p.b };

      var result = q.FirstOrDefault();  // catch running past end of table
      if (result == null)
        return -1; 

      return q.First().a;  // return real data
    }

Upvotes: 4

Views: 5860

Answers (3)

Jon Skeet
Jon Skeet

Reputation: 1499770

You can use FirstOrDefault instead:

var result = q.FirstOrDefault();
if (result == null)
{
    // Query results were empty
}

Note that there's no way of telling between "a real result which is the default value for the element type" and "no results"... it's not a problem here, as all your real results are non-null references, but it's worth being aware of.

EDIT: I hadn't noticed that you were using a custom struct; I'd misread it as an anonymous type. I'd strongly recommend using an anonymous type here instead of a mutable struct. Or, given that you only need mdA anyway, you could use:

var q = from p in db.pos
        where (p.a >= a && p.b > b) || (p.a > a && p.b > 0)
        orderby p.a, p.b
        select (int?) p.a;

int? result = q.FirstOrDefault();
if (result == null)
{
    // No results - take whatever action
}
else
{
    // Got a result - find the underlying value...
    int a = result.Value;
}

Upvotes: 10

Bodrick
Bodrick

Reputation: 342

You can use FirstOrDefault() to avoid the InvalidOperationException. In the following example, x will be null if q has no elements. You can then check this and proceed accordingly.

var x = q.FirstOrDefault ();

return x == null ? -1 : x.mdA;

Upvotes: 2

TehBoyan
TehBoyan

Reputation: 6890

Instead of First() use FirstOrDefault() and then check for null value before using it.

var rResult = q.FirstOrDefault();
if(rResult != null)
{
   var something = rResult.mda;
}

Upvotes: 3

Related Questions