1

Assume I have an entity in my (Code First) Entity Framework model that looks like this:

public class Foo
{
  [Key]
  [MaxLength(50)]
  public string FooId { get; set; }

  [Timestamp]
  [ConcurrencyCheck]
  public byte[] Version { get; set; }
}

Assume further that I need to fetch the most recent few of these items. I can do that with a fairly simple LINQ expression, which gets translated into the correct SQL, and runs fine.

var recentFoos = db.Foos.OrderBy(f => f.Version).Take(10);

Now, if that query happens in a method that I also want to test, things get more complicated. I have a setup with fake context and entity collections, and that all works fine. But, because byte[] can't be sorted directly, trying to execute that code throws an ArgumentException ("At least one object must implement IComparable.").

On the other hand, if I use the overload of OrderBy() that take a comparer, that will run in memory, but throw an exception ("…this method cannot be translated into a store expression.") trying to run against the database.

Is there a way to either a) write a single LINQ query that will run correctly in both circumstances, or b) to reliably detect which case pertains, so that my code can sort using the correct overload?

6
  • 1
    The query should be written in a way that is supported by the real query provider (LINQ to Entities in this case), i.e. exactly how you did it. It's the problem of your fake context implementation, so you need to find a way to correct it there, rather than trying to adjust the production code for testing (the last sounds absurdly to me). Commented Sep 14, 2016 at 23:32
  • OK. Do you have any concrete suggestions about how to make that work? The fake context setup is pretty standard (see msdn.microsoft.com/en-us/library/dn314429.aspx). Commented Sep 14, 2016 at 23:55
  • And you are standartly failing in what they mentioned as Limitations of EF in-memory test doubles (and many cases they didn't mentioned like using canonical functions that work only in LINQ to Entities or using CLR methods that work only in LINQ to Objects). That's why I'm against testing EF with fakes, I don't do that and have no problems. Good luck. Commented Sep 15, 2016 at 0:10
  • Ivan is right, the correct place to do something special to enable testing is in the fake context implementation if at all possible. I need to know what your fake context setup looks like but I would suggest intercepting and rewriting the expression tree with a simple visitor that replaces the OrderBy call with the comparer overload. Once I know what your fake code looks like I can probably write up an answer. Commented Sep 15, 2016 at 13:23
  • It's pretty much Microsoft's sample code, as described in the link I posted earlier (including the fake async provider stuff). If I get the time today, I'll see about maybe gist-ing the actual sources from the project. What you're describing seems like a reasonable approach, though. Commented Sep 15, 2016 at 16:49

1 Answer 1

0

I ended up implementing the solution jnm2 suggested: writing an ExpressionVisitor to rewrite the query from the predicate-only overload used by normal queries to the overload necessary for in-memory querying. I had to rework the original Microsoft sample code for fake DbSet to allow these visitors to be plugged in and used at the right moment.

A Gist with my code can be found here. If anyone can suggest a more elegant way to apply the visitors, I'm definitely open to suggestions.

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.