Monthly Archives: December 2013

Using Pre-Generated Views Without Having To Pre-Generate Views (EF6)

To be able to work with different databases Entity Framework abstracts the store as a set of views which are later used to create queries and CUD (Create/Update/Delete) commands. EF generates views the first time it needs them (typically on the first query). For bigger or more complicated models view generation may take significant time and negatively impact the startup time of the application. This can be worked around by generating views at design time (e.g. using EF Power Tools or my T4 templates for generating views) and compiling them into you EF app.

Notes:

  • There were significant improvements to view generation in EF6 (and more is coming), so make sure using pre-generated views visibly improve the startup time of your app – if they are not – don’t bother.
  • In EF6 (6.0.0 and 6.0.1) we saw several performance regressions (mostly in Code First) that affected the startup time of apps. They were not related to view generation (which in fact in most cases was faster than it was in EF5) so adding pre-generated views does not help. Many of these were fixed in 6.0.2. Always make sure you are running the latest bits and again check if view generation helps – if it does not – don’t bother.

So, for bigger models pre-generated views can help. But they are a bit bothersome. You need to remember about regenerating them each time your model changes. They add to the build time. They make your project more complicated. Not having to worry about views (especially that they are just an implementation detail that ideally would not be even exposed publicly if view generation did not impact the startup performance) makes the life of the developer much easier. Can we somehow combined these two worlds (and not in the way that the manual work done at design time impacts the startup time of the application :))? For instance, what if EF could check at runtime if up-to-date views are available and then use them if they are, or – if no usable views are available – it generates new views and stores them so that they are used the next time the application is run? This way the first time your app starts it will spend some time creating views (this time has to be spent somewhere anyways) but then (assuming the model has not changed) it will just use the views created when the app was run the first time which should result in faster startup time for subsequent runs. Sounds nice doesn’t it? And it actually is now possible. With the EFInteractiveViews NuGet package I published recently you can achieve all this with just a couple lines of code!

So, how does this work?

Assuming you have an existing EF6 application add the EFInteractiveViews NuGet packageto your project – you can right click on the References node in your project, select “Manage NuGet Packages” and add the NuGet package from the UI, or use the following command from the Package Manager Console:

Install-Package EFInteractiveViews

Once you add the package you need to decide where you want to store your views – you can use either a file or the database. If you want to store views in a file add the following code to your app:

using (var ctx = new MyContext())
{
    InteractiveViews
        .SetViewCacheFactory(
            ctx, 
            new FileViewCacheFactory(@"C:\MyViews.xml"));
}

Note that this code has to be executed before EF needs views (typically before you send the first query or the first call to the .SaveChanges() method) so make sure it is in the right place (for instance in a static constructor). The above line registers a view cache factory. Now if EF needs views it will first ask the registered view cache factory for views. The FileViewCacheFactory tries to load views from the file – if the file exists and the views match the model it will return views and EF will not need to generate views. If, however, the file does not exist or the views are outdated the FileViewCacheFactory will generate views, save them to the file and return them to EF.
Storing views in a file is kind of cool but since this is an EF app it has to have a database. Therefore storing views in the database would be even cooler. And this actually is possible – you just need to register a different view cache factory included in the package:

using (var ctx = new MyContext())
{
    InteractiveViews
        .SetViewCacheFactory(
            ctx, 
            new SqlServerViewCacheFactory(ctx.Database.Connection.ConnectionString));
}

Similarly to the FileViewCacheFactory you need to register the SqlServerViewCacheFactory before EF needs views. One more assumption the SqlServerViewCacheFactory makes is that the database exists (if this is not the case and you are using CodeFirst you can create one with ctx.Database.Initialize(force)). The SqlServerViewCacheFactory creates a table in your database to store views. By default the table will be called __ViewCache and will be in the dbo schema. You can change the defaults by passing the name of the table and/or schema in the SqlServerViewCacheFactory constructor.
As you probably guessed the SqlServerViewCacheFactory class is Sql Server specific. What if you are using a different back end? That’s not a big deal too. Create a new class derived from the DatabaseViewCacheFactory and implement three simple abstract methods – CreateConnection(), ViewTableExists() and CreateViewTable() and you are done. Since the EF Interactive Views project is open source you can take a look how I did it for SqlServer. (and yes, the DatabaseViewCacheFactory uses EF6 under the cover to get and update views in the database).

Words of precaution

When using interactive views make sure that you are not running different versions of an app (with different models) against the same database (CodeFirst typically does not allow this unless you are not using an initializer). If you do one version of an app will create views and then the other will not be able to use them so they will be overwritten which will make the views unusable for the version that ran originally and there will be no benefit in using interactive views at all.

That’s pretty much it. As I mentioned above the project is open source and you can find code on codeplex at https://efinteractiveviews.codeplex.com/. Just in case here is the link to the NuGet package: https://www.nuget.org/packages/EFInteractiveViews. Use, enjoy, comment and file bugs!