2

I was having an issue with a LINQ query today and after some debugging I was able to resolve the issue but it seems like a bug to me in the way LINQ works. Here is what I had:

var myitem = context .items .OrderByDescending(x => x.DateEdited) .FirstOrDefault(x => x.fkId == myFkId && x.DateEdited < someDate); 

In my database I have a table with some records and I want to retrieve the most recent record that is older than "someDate" and who has a particular foreign key in a column. The above query did not work however. It was returning the oldest record with the matching foreign key. I ended up having to rewrite my query like this to get it to work:

var myitem = context .items .Where(x => x.fkId == myFkId && x.DateEdited < someDate) .OrderByDescending(x => x.DateEdited) .FirstOrDefault(); 

In my debugging I found out that the "x.DateEdited < someDate" was re-ordering the IEnumerable so I ended up having to put my OrderByDescending clause after the date check.

Has anybody else run into this issue? Is it a bug or expected functionality?

2
  • 1
    Note that regardless of expected behavior the 2nd query is much more efficient, since you are filtering the rows before ordering them. Commented Feb 21, 2011 at 17:34
  • Could you post the relevant SQL generated? Commented Feb 21, 2011 at 17:34

2 Answers 2

3

Even though .OrderByDescending() returns an IOrderedEnumerable, the .FirstOrDefault() is a shortcut to .Where() which only returns an IEnumerable which does not guarantee order.

Basically, adding a filter does not guarantee the order of the data. If you look at the generated SQL from the first, you will get a nested subresult from the orderby that is then filtered again.

Sign up to request clarification or add additional context in comments.

2 Comments

This doesn't make much sense when you think about how IEnumerables and LINQ should be working. So, OrderByDescending returns an IEnumerable with a known ordering. For FirstOrDefault to process the input out of sequence, either it's pulling the entire IEnumerable until the end, processing, then returning. Or the input is actually going thru an IEnumerable which is not in order. Then again, the entire query is being translated into a SQL statement, so I would call it a quirk in translating the expression into SQL.
@Rich - whilst your logic is correct, and the implementation of FirstOrDefault(selector) in Linq to Objects will almost certainly iterate the incoming sequence in the order it was provided, the contract does not guarantee that. The signature in L2S is identical, but we get random order back, and no contracts have been broken.
1

Generally, if an operation does not explicitly define the output order, you can't depend on the result being in any particular order until you specify/apply it yourself.

Unless you know that ordering an intermediate result will yield performance improvements in the next step of an algorithm, there's no reason to so. Just apply the ordering as a final processing step.

2 Comments

I see so even though I ordered them before I did my firstOrDefault I can't count on the order to carry through? Interesting.
Pedantic, but yes that is the case.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.