Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to test whether a given expression can be converted to SQL *without* connecting to a SQL database?

For example:-

// This one will be converted to SQL no problem
Expression<Func<Foo, bool>> predicate = x => x.Name = "Foo";

// This one will throw a NotSupportedException because the QueryProvider
// doesn't support reference comparisons
Expression<Func<Foo, bool>> predicate = x => x == someOtherFoo;

// This one doesn't work because the query provider can't
// handle IsAwesome()
Expression<Func<Foo, bool>> predicate = x => x.IsAwesome();

I'm looking for a way to test this before runtime, ideally in an automated test isolated from the database.

I spent some time trawling through MSDN trying to find how to instantiate my own QueryProvider, but my Google-fu appears to be failing me today.

Thanks in advance!

like image 489
Iain Galloway Avatar asked Oct 25 '12 15:10

Iain Galloway


1 Answers

You need a model to do this, but you don't need a database. You can create the model as an EDMX, but it's probably easier to use Code First. To ensure that the creating or using the Code First model doesn't need a database connection you will need to provide some information that Code First normally obtains from the database. This post http://blog.oneunicorn.com/2012/04/21/code-first-building-blocks/ shows how to use the DbModelBuilder to do this and how to create a DbContext from the model. You'll end up with some code like this:

var modelBuilder = new DbModelBuilder();
modelBuilder.Entity<Foo>();
var model = modelBuilder.Build(
                new DbProviderInfo("System.Data.SqlClient", "2008")).Compile();

You'll probably want to cache the model object rather than create it again for every different test.

You should also disable database initializers to prevent DbContext from attempting to connect to the database. For example, before using the context make a call like this:

Database.SetInitializer<FooContext>(null);

Now you can just use ToString on any query to see what SQL it will generate. If LINQ can't handle the expression then you will get an exception. For example, this will print the query:

using (var context = new FooContext(model))
{
    Expression<Func<Foo, bool>> predicate = x => x.Name == "Foo";

    Console.WriteLine(context.Foos.Where(predicate));
}

This will throw:

using (var context = new FooContext(model))
{
    var someOtherFoo = new Foo();
    Expression<Func<Foo, bool>> predicate = x => x == someOtherFoo;

    Console.WriteLine(context.Foos.Where(predicate));
}

Obviously if you're writing tests you won't just be printing to the console, but rather performing some kind of assertions/checks.

like image 122
Arthur Vickers Avatar answered Oct 29 '22 15:10

Arthur Vickers