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!

90 thoughts on “Using Pre-Generated Views Without Having To Pre-Generate Views (EF6)

  1. Hi Pawel!!!

    Very good hack.. You now EF6Contrib.codeplex.com? would be great if you put this as a contribution in this project…

    Thanks!

    unai

    Like

  2. Hi, I downloaded the source code to your project (I had to convert it from .Net 4.5 to .Net 4, but didn’t make any other changes), built it, added it to my project, and added the using statement you have listed above (but with my context) and it doesn’t create the xml file. I tried an absolute and relative path and nothing is created. Also no exceptions are thrown.

    Is there a way to verify that a View is being used?

    Like

    1. If the file has not been created then view generation was mist likely not invoked. I don’t think it has anything to do with the target version of the .NET Framework. Rather I would double check whether the factory is registered correctly. Note that it has to be registered before any query has been sent to the database otherwise EF will automatically generate views. One hack way of making sure that view generation is/is not invoked is to provide an invalid path (e.g. with non-existing disk drive). If view generation is invoked you should get an exception.

      Like

      1. Thanks for the quick reply. I created a new project and this time it worked. I believe the reason it didn’t work before was because I was initially only using it during my Unit test (and hadn’t tried it in production code) where I’m using Effort’s In-memory solution. It seems that for whatever reason the ViewCacheFactory.Create() method doesn’t get called with Effort, so no Save() happens. Effort wasn’t exactly compatible with the Views used by EF Power Tools, but this seems to go along with it well. Thanks for making this!

        Like

        1. I haven’t tried Effort so I don’t know why interactive views wouldn’t be invoked in this scenario. I am glad you were able to make the interactive views work!

          Like

  3. Hello !
    I have Visual studio Ultimate 2013., and EF 6.1.
    I’m working on a Visual Basic Project.
    – I have installed the package on console manager : Install-Package EFInteractiveViews

    – after on my main form I add the following sub :

    Imports InteractivePreGeneratedViews

    Private Sub IntViews()
    Usingctx = New MyEntities()
    InteractiveViews.SetViewCacheFactory(ctx,NewFileViewCacheFactory(“C:\Myprog\MyViews.xml”))

    End Using
    End Sub

    But I get 2 erros :

    Error 104 : ‘InteractiveViews’ is not declared. It may be inaccessible due to its protection level.
    Error 105 : Type ‘FileViewCacheFactory’ is not defined.

    What can I do ?

    Thank you !

    Like

    1. Double check your references. What often happens to me when installing packages from the Package Manager Console in a solution that has multiple projects is that I forget to select the project and the packages are installed to a different project.

      Hope this helps,
      Pawel

      Like

  4. Hello !
    The strange is that i have these errors , i execute again the installation command on package manager , after the execution the errors disappear , but if i run the application the errors appear again and remain (so i can’t run).

    Like

    1. Are you by any chance targeting.Net Framework 4? Another way to troubleshoot would be to enable diagnostic output from the build and see what is really happening.

      Like

        1. I believe this is the issue. The NuGet package contains only the net45 version of the assembly. If you build your project with the diagnostic output you should see a warning saying that the assembly you are trying to reference was built with a newer version of the .NET Framework than the one your app is targeting and therefore it cannot be referenced. As a result your project behaves as if the assembly was not referenced. I am thinking about shipping a 1.0.1 version that will contain both net40 and net45 versions of the assembly (or just net40 since it should work for both and I don’t think there is any code there that requires .NET Framework 4.5) since I have already seen a couple requests for this.

          Thanks,
          Pawel

          Like

  5. Hello !
    I have a question : How can I use Interactive Pre-Generated views on my situation :
    I have a project in vb.net and EF 6. When the application run , he connects with a database ( let say db1). After the users can change the database to another IDENTICAL database (db2).
    what should I do to make work this scenario with Interactive Pregenerated views ?
    Thank you !

    Like

    1. How do you know that the views are not being used for the second database (db2)? I don’t know from the top of my head how MetadataWorkspaces are cached but I think there are two possibilities – if the MetadataWorkspace created for the 1st database is being reused for the 2nd database (I think EF will re-use the MetadataWorkspace because it’s about the model and not the database but I am not 100% positive) then it should already have views and should continue to use them. If EF doesn’t re-use the MetadataWorkspace it would have to go through the initialization process and would invoke view generation again. It should use interactive views though because the view cache factory is still being registered.

      Like

  6. Hi there,

    So I am running EF6.1.1-beta1 (cannot use release due a bug that was fixed) and have your package. I do not see any performance benefit to the pre-generated views. The XML output file is 1.3 mb to give you an idea how large my model is, so I am curious if there is an incompatibility with the pre-release EF or if there is no gain from an OM this size (xml serialization time equaling the EF generation time?)

    Thanks!

    Like

    1. Just want to add I went back to the T4 template and that does save some load time, 11 seconds. I also needed to modify the T4 template to use the EF the project is using and not the EF loaded by Visual Studio (check the Location of the GetEFAssembly function – it will come from the IDE which won’t be the latest..) HTH!

      Like

      1. This is interesting. Are you using the latest version of the T4 template? I just double checked and what it does is that it loads the target assembly of the project and it goes up the inheritance chain to find the DbContext type. I remember that I had to change the template to do things this way in order to work around a problem where two EntityFramework.dll assemblies would be loaded to a single AppDomain (in different load contexts) if I referenced the EntityFramework.dll directly using the ‘@assembly’ instruction. Doing this felt safer than loading random assemblies from disk and I also remember that when I tried loading assemblies directly the T4 transformation engine would lock them until the AppDomain got shut down (the T4 transformation engine spins an AppDomain and re-uses it for several transformations) which caused build failures since files could not be overwritten.
        Question: does the template break without the change you introduced (i.e. when it is not using the latest version of the EntityFramework.dll)? If so, what is the exception?

        Thanks,
        Pawel
        Thanks,
        Pawel

        Like

    2. Are you sure you registered the view cache factory correctly? Are views being saved to the database/file correctly? If they are not then probably the view cache factory is not registered correctly and EF does its own thing.

      Thanks,
      Pawel

      Like

      1. Hi there,

        Pre-Generated views via code:

        Well I see the file being created (1.4 mb with lotsa views in it) and the timestamp does not change with multiple runs so that implies that the model is being generated and reused but the my unit tests run slower with it, with the bulk of the init time being taken in SetViewCache. I suppose I could grab the source and see what’s happening. Maybe some tracing would be helpful. 🙂

        T4 Template:
        I just got the T4 template via nuget yesterday, version 1.0.1. So as I said, I am running the 6.1.1-beta1 version of EF. Unfortunately the EF team in their wisdom did not change the version number of the assembly, it’s still 6.0. Because of that, once the EF DLL is loaded by VS, it will not load this newer version that is used by by DbContext. So, debugging the template, if I have run it, the Assembly Location for EF is Program Files (x86)\Microsoft Visual Studio 12,0\Common7\IDE\EntityFramework.dll and I run into the 6.1 bug with underscores in column names (metadata store cannot add column bla bla bla.) If I specify the version using

        everything will work fine, as long as I am the first load of EF, otherwise I get this error:

        Error 124 Running transformation: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. —> System.TypeInitializationException: The type initializer for ‘System.Data.Entity.Internal.AppConfig’ threw an exception. —> System.InvalidCastException: [A]System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection cannot be cast to [B]System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection. Type A originates from ‘EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089’ in the context ‘Default’ at location ‘C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\EntityFramework.dll’. Type B originates from ‘EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089’ in the context ‘LoadFrom’ at location ‘C:\Users\boffo\AppData\Local\assembly\dl3\OL9GTRMA.0ZO\K6VPHH54.88D\7b50d55c\4c1e487f_f979cf01\EntityFramework.dll’.
        at System.Data.Entity.Internal.AppConfig..ctor()
        at System.Data.Entity.Internal.AppConfig..cctor()

        With all this being said, I believe this to be the fault of the EF team for not changing the version numbers on the beta build.. I suppose I can simply replace the dll in the VS directory…..

        Like

        1. EntityFramework.dll assembly versioning is quite an interesting topic. If you check the commit log you should be able to find that after EF6 was shipped the assembly version actually changed for a little while and then the change was reverted. We spend at least a couple of weeks debating whether to change the assembly or leave it as is and the final decision was to leave it as is for quite a few reasons with the most important being the impact to our partners whose products depend on EF (like MVC or Identity) and the impact to the users who use EF with third party databases (providers would have to be rev’ed each time a new version of EF was shipped even though the provider model is kind of set in stone for all EF 6.x releases).
          With regards to the template – I would have to check this but the changes I made to use reflection was specifically to avoid this InvalidCastException. The thing I don’t understand is who is loading the EntityFramework.dll shipped from tooling unless… in the same instance of VS you first did some T4 transformation using a template that loaded EntityFramework.dll. While there is a general problem with EntityFramework.dll that lives in the Common7\IDE directory (see bugs https://entityframework.codeplex.com/workitem/2065, http://entityframework.codeplex.com/workitem/1183 and the connect issue http://connect.microsoft.com/VisualStudio/feedback/details/806693/the-provider-did-not-return-a-providermanifest-instance-in-vs-2013-and-entityframework-6) the real issue is between VS (that generally does not run add-ons in a separate AppDomain) and VS add-ons/tools/extensions which use EntityFramework.dll (EF Tooling is the best example but any tooling which depends on EntityFramework.dll will do the same – load EntityFramework.dll into the AppDomain VS is running). However, this should not affect T4. The reason for this is that T4 actually creates its own AppDomain to run transformations. The problem is however that the AppDomain T4 creates is actually re-used for a few subsequent transformations and then is shut down so if any of the transformations loaded the EntityFramework.dll into the AppDomain it will stay there untill the AppDomain is unloaded.
          From the InvalidCastException details it actually appears to me that updating EntityFramework.dll in the Common7\IDE would not fixe the problem. Moreover I believe (because I spend quite a few hours looking into it, and also tried) that you would get the exception even if you had the same copies of the assembly in both places. The InvalidCastException happens not because the versions are different but because there are two EntityFramework.dll assemblies in one AppDomain that are loaded in two different load context (one is loaded in the ‘Default’ context and the other one in the ‘LoadFrom’ context – it is in the exception message and if you turned Fusion logging you would see the same) and for CLR the two contexts are separate worlds. This actually was the rationale for this https://github.com/moozzyk/EF6CodeFirstViewGenT4TemplateCSharp/commit/e60084c369d5585f2467e78f41cf3865a7019a6d change which was supposed to fix the problem within my template but cannot fix the problem if EntityFramework.dll had been loaded before my template was run. Do you know if the error happens if you close and re-open VS and run the view gen template as the first thing after opening?

          Thanks,
          Pawel

          Like

      2. Okay, I downloaded the code and see where the issue is. Keep in mind I have a very large object model. Looking in interactiveviews, setviewcachefactory you have a line: ((IObjectContextAdapter)context).ObjectContext to get the object context. This causes the context to be created and fully populated before your mappingviewcache factory is wired up. You can check it yourself, toss in a breakpoint and check the metadataworkspace in the debugger. So I don’t believe this particular way of doing this would work at all. I’m looking into alternative ways to get at the metadata workspace or the underlying objectcontext without creating it now… but open to ideas! 🙂

        Like

        1. Yes, `((IObjectContextAdapter)context).ObjectContext` will force loading the metadata which is needed to set the viewCacheFactory. This should not be a big deal when running an app in the production since metadata initialization runs only once per context per AppDomain and it has to happen anyway before the first query is executed. I agree that when you run unit tests this might be an issue if your tests can run without metadata being initialized. Another interesting point is that I actually think this is a usability bug in EF because the registration should not happen at such a low level and in addition I should not have to keep a reverse look up (mappingItemCollectionLookUp) to be able to generate views. I talked to some people on the EF team and they agreed with me but it was kind of low on the priority list (especially given all the improvements made to view generation in EF6+). In addition after EF6 was shipped I also considered it less pressing since I wanted the project to continue to work with all EF6.x versions.
          In general my idea to fix this was to add a hook in DbConfiguration which I could use to register a method that would be called when EF needs views and which would get the StorageMappingItemCollection as a parameter. This way the metadata would be initialized when EF needs it instead of force initializing it just because you need to set a viewcachefactory.

          Thanks,
          Pawel

          Like

      3. Hi Pawel, thank you for your informative replies. So what I have discovered is a difference between running the T4 in Interactive Debug vs. Right click run. RightClick run does not work for me, even if it’s a fresh run, but Debug does.

        Thanks for talking with the EF team about the IObjectContext thing. Yes, everything does work and it’s low priority but why bother pre-gen’ing the views? For me, at my shop, we have a rather large object model which takes 30-40 seconds to init. That’s fine in prod, warm up script and never deal with it again, but my developers (myself included) are a particularly whiny bunch and the load time is a bit annoying when you get yourself stuck in a churn… Happy to share the OM or schema..

        I’ve also confirmed that there isn’t any time saved by using the DbMappingViewCacheType attribute either. We did a jump from an older version of EF, I want to say 3, to 6. At 3, the pre-gen views did save quite a bit of dev time..

        Again, thanks for your help, I’ll just keep an eye out for future versions.

        Like

        1. View generation has been greatly improved in EF6 (and there were further improvements in EF6.1). AFAIR in some scenarios view generation is now even 100 times faster. If you don’t see any start-up time improvement with pre-generated views it may mean that this is not view generation that is causing the delay. Since you have the T4 template quasi working you can check how long it takes to generate the views when using the template. The template is doing what the app would be doing at runtime so it should take approximately the same time. If the template needs for instance 2 secs to generate views then the delay of 30-40 secs at the app start up would indicate that something else is causing the delay. This “something else” would be the time needed to build the model in which case you want to take a look at this bug report: https://entityframework.codeplex.com/workitem/1749 (read the comments, they are not only insightful but contain links to related bugs) which in turn contains link to this document: http://msdn.microsoft.com/en-US/data/dn582034. Finally if you have not seen it yet the Performance Consideration white paper (http://msdn.microsoft.com/en-US/data/hh949853) has been updated very recently and takes EF6 into consideration. It might be worth looking at.
          Side note 1: Jiri hit a similar problem with InvalidCastException you did. From our conversation it appears I was wrong about the exception happening even if the versions of the assembly loaded in different contexts are the same. This would also mean that the workaround for the issue would be install the latest tooling and if you are using the latest runtime you should not see the exception. You can see the discussion here: https://entityframework.codeplex.com/discussions/547644
          Side note 2: In VS2012 Update1 we (I was on the EF team at that time so I count ;)) introduced the CleanUp behavior T4 directive which is shutting down the app domain after each transformation (in order to free up resources). I wonder if adding this directive to the T4 template would fix the problem (probably after the first transformation). You may try adding this to the T4 template
          <#@ CleanupBehavior processor="T4VSHost" CleanupAfterProcessingtemplate="true" #>
          as the first line (if this does work I will update the template and re-publish).

          Thanks,
          Pawel

          Like

  7. Hello !
    Is there any way on runtime to detect if EF is using the MyViews.xml file that is created by interactive views ?
    Thank you !

    Like

  8. The file is re-created when I start the application , but I want to know if is used when a query is executed during runtime.

    Like

    1. If the file is created then the generated views should be used. There is no easy way to tell that apart from compiling EF code in the debug mode, setting a breakpoint, running your app and debugging when the breakpoint gets hit.
      What is your concern?

      Thanks,
      Pawel

      Like

      1. ok, I’m also confused if the View is used or not. I registered it and see the generated XML.

        I used WPR.exe to collect a ETW trace and compared the stacks and the only difference between the trace where I use the views are those line after EntityFramework.dll!System.Data.Entity.Core.Mapping.StorageMappingItemCollection+ViewDictionary::SerializedGetGeneratedViews:

        Line #, DPC/ISR, Process, Stack Tag, Stack, Count, TimeStamp, % Weight
        45, , , , | | | | | | | | | | | | | | | | | | | | | | | | |- EntityFramework.dll!System.Data.Entity.Core.Mapping.StorageMappingItemCollection+ViewDictionary::SerializedCollectViewsFromCache, 358, , 0,08
        46, , , , | | | | | | | | | | | | | | | | | | | | | | | | | |- EntityFramework.dll!System.Data.Entity.Infrastructure.MappingViews.DbMappingViewCacheFactory::Create, 353, , 0,07
        47, , , , | | | | | | | | | | | | | | | | | | | | | | | | | | |- InteractivePreGeneratedViews.dll!InteractivePreGeneratedViews.ViewCacheFactoryBase::GenerateViews, 310, , 0,07
        48, , , , | | | | | | | | | | | | | | | | | | | | | | | | | | | EntityFramework.dll!System.Data.Entity.Core.Mapping.StorageMappingItemCollection::GenerateViews, 310, , 0,07
        49, , , , | | | | | | | | | | | | | | | | | | | | | | | | | | | |- EntityFramework.dll!System.Data.Entity.Core.Mapping.StorageMappingItemCollection::GenerateViews, 308, , 0,07

        the stack of the non used View goes directly to EntityFramework.dll!System.Data.Entity.Core.Mapping.ViewGeneration.ViewgenGatekeeper::GenerateViewsFromMapping which is also called when I use views.

        this is the same in both cases (with and without view.xml):

        Line #, DPC/ISR, Process, Stack Tag, Stack , Count, TimeStamp, % Weight
        50, , , , | | | | | | | | | | | | | | | | | | | | | | | | | | | | EntityFramework.dll!System.Data.Entity.Core.Mapping.ViewGeneration.ViewgenGatekeeper::GenerateViewsFromMapping, 308, , 0,07
        51, , , , | | | | | | | | | | | | | | | | | | | | | | | | | | | | |- EntityFramework.dll!System.Data.Entity.Core.Mapping.ViewGeneration.ViewgenGatekeeper::GenerateViewsFromCells, 283, , 0,06
        52, , , , | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |- EntityFramework.dll!System.Data.Entity.Core.Mapping.ViewGeneration.ViewGenerator::GenerateAllBidirectionalViews, 226, , 0,05
        53, , , , | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |- EntityFramework.dll!System.Data.Entity.Core.Mapping.ViewGeneration.ViewGenerator::GenerateDirectionalViews, 172, , 0,04
        54, , , , | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |- EntityFramework.dll!System.Data.Entity.Core.Mapping.ViewGeneration.ViewGenerator::GenerateDirectionalViewsForExtent, 155, , 0,03
        55, , , , | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |- EntityFramework.dll!System.Data.Entity.Core.Mapping.ViewGeneration.ViewGenerator::GenerateViewsForExtentAndType, 125, , 0,03
        56, , , , | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |- EntityFramework.dll!System.Data.Entity.Core.Mapping.ViewGeneration.QueryRewriting.QueryRewriter::GenerateViewComponents, 87, , 0,02
        57, , , , | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |- EntityFramework.dll!System.Data.Entity.Core.Mapping.ViewGeneration.QueryRewriting.QueryRewriter::EnsureExtentIsFullyMapped, 42, , 0,01
        58, , , , | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |- EntityFramework.dll!System.Data.Entity.Core.Mapping.ViewGeneration.QueryRewriting.QueryRewriter::RewriteQuery, 31, , 0,01
        59, , , , | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |- EntityFramework.dll!System.Data.Entity.Core.Mapping.ViewGeneration.QueryRewriting.QueryRewriter::RewriteQueryCached, 23, , 0,00
        60, , , , | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |- EntityFramework.dll!System.Data.Entity.Core.Mapping.ViewGeneration.QueryRewriting.RewritingProcessor`1[System.__Canon]::RewriteQuery, 18, , 0,00
        61, , , , | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | EntityFramework.dll!System.Data.Entity.Core.Mapping.ViewGeneration.QueryRewriting.RewritingProcessor`1[System.__Canon]::RewriteQueryOnce, 18, , 0,00
        62, , , , | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |- EntityFramework.dll!System.Data.Entity.Core.Mapping.ViewGeneration.QueryRewriting.RewritingPass`1[System.__Canon]::RewriteQuery, 15, , 0,00
        63, , , , | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |- EntityFramework.dll!System.Data.Entity.Core.Mapping.ViewGeneration.QueryRewriting.RewritingPass`1[System.__Canon]::RewriteQuery, 13, , 0,00
        64, , , , | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |- EntityFramework.dll!System.Data.Entity.Core.Mapping.ViewGeneration.QueryRewriting.RewritingSimplifier`1[System.__Canon]::TrySimplifyJoinRewriting, 6, , 0,00
        65, , , , | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |- EntityFramework.dll!System.Data.Entity.Core.Mapping.ViewGeneration.QueryRewriting.RewritingSimplifier`1[System.__Canon]::SimplifyRewriting, 5, , 0,00
        66, , , , | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |- EntityFramework.dll!System.Data.Entity.Core.Mapping.ViewGeneration.QueryRewriting.RewritingSimplifier`1[System.__Canon]::SimplifyRewritingOnce, 3, , 0,00

        So the views are being generated again from the model (GenerateViewsFromMapping) in both cases.

        This is why I’m also confused if the generated view is used or not.

        I use the latest 6.1.3 and stay for it for a while, because EF7 misses too many things when it gets released. So I can’t test if EF7 improves it (also because the firebird provider is not available for EF7).

        Like

        1. From the trace it looks like either the file containing views cannot be found or the hash did not match. Take a look at the ViewCacheFactoryBase.Create method – it will call GenerateViews if it can’t obtain views.
          On a separate note – are you sure you need views? When using EF6 views are useful if the model is really big (e.g. at least a few hundreds of entities…)

          Pawel

          Like

      2. I don’t know if I need the View or not. I noticed a high CPU usage spike where 1 core is fully used. So I used WPR to trace it and saw those EF View calls in WPA.exe and found your post here and tried the EFInteractiveViews. Now I need to verify if the generated View is used and if I get a benefit or not. I rena,ed the old XML, and the XMl gets generated again. I used WinMerge to compare them and both are the same.

        Like

        1. If EFInteractiveViews cannot find views or views have changed (as a result of a change to the model) the views will be regenerated. Otherwise the views should be loaded from the file (or the database). So, when the views from the file should be used after you ran your application once (when they will be generated). EF doesn’t make it easy to tell if the views it is using are pre-generated or not.

          Like

      3. My model doesn’t change. As I said, the XML is always the same size with the same content (after renaming the old one, so that your lib regenerates it again) and I really want to know if EF uses the XML or not so that I can detect if I have a benifit or not. this is why I also asked the EF Team some time ago to add EventSource/ETW logging, so that we can see/trace what EF does in background. But they have no plans to add this 😦

        Like

        1. I believe that views are being used in your case – the file is created and is not changing. Unfortunately there isn’t an easy way of checking this (short of setting a breakpoint in the EF code). You said, you were concerned about the CPU spike – I am not sure if I understand why it is a problem if it does not last long and the application startup time is reasonable.
          Anecdotally – I was on the EF team when the ETW tracing was removed. It was polluting the code a lot and – after talking to support folks – we couldn’t find anyone who found it useful.

          Like

      4. ETW is a large learning curve, but is blows all other tracing away. Setting a breakpoint is not possible in production, but capturing a trace is much better to see what is going on. I really hope it comes back.

        I’ll now anaylze a bit more if the views are used or not.

        Like

  9. The file is re-created because there’s the code on application start that do this thing ( The code that you have posted in the article ).
    I want to know if EF is really use these generated views , because I don’t see any difference in performance when I use the EF Interactive PreGenerated Views or not use it.
    If I should use a breakpoint where to make this and what should I see to make sure that is used ?
    Thank you !

    Like

    1. I am sorry for the delayed response. You should set the breakpoint in the EF source in the StorageMappingItemCollection.cs file (entityframework\src\EntityFramework\Core\Mapping\StorageMappingItemCollection.cs) on lines 109 and 114. The first breakpoint should be before EF tries to read views the second is where it wants to generate views. In general the first condition should be true while the second (i.e. if (extentMappingViews.Count == 0)) should be false. Note that this code will be hit twice and you should ignore when it gets hit for the first time. The first hit is for the DbContext derived type EF internally uses for migrations.

      Hope this helps,
      Pawel

      Like

      1. Hello !
        Sorry but I can’t find StorageMappingItemCollection.cs in my project.
        I’m using VB.net , but I can’t find even StorageMappingItemCollection.vb.
        Only on References in my project I found StorageMappingItemCollection but I can’t set a breakpoint

        Like

  10. Great Job – Very Easy to use. When using the SqlServerViewCache, could you add an option to save the view column as a varbinary instead of nvarchar(max). This would make the pull a lot quicker when dealing with very large models. Just a thought. You could even have it set up to save nvarchar for debug purposes but release used the varbinary column.

    Like

    1. Thanks. I have not measured what the performance difference between `nvarchar(max)` and `varbinary(max)` would be but I could not find anything on the web that would indicate it is significant (if any). On top of that if I wanted to save views as binary data I would probably have to convert it back to text which would reduce/remove the performance gain you would get by using `varbinary(max)` data type. Finally, since views are text it is more natural to store them in a text oriented column and not as binary data. Having said that – I tried to make it easy to write your own view cache factories by deriving from existing classes so it should be easy for you to extend the functionality and use a column of `varbinary(max)` type to store views.

      Thanks,
      Pawel

      Like

  11. Hi,

    I think this is a great tool & implementation. Unfortunately it is not working my project and I can’t work out why.

    This code is called from the constructor of my DataContext (inherits from DbContext):

    private static bool _isPreGeneratedViewCacheSet;

    private void InitializationPreGeneratedViews()
    {
    if (_isPreGeneratedViewCacheSet) return;

    var precompiledViewsFilePath = new FileInfo(Assembly.GetExecutingAssembly().Location).DirectoryName + @”\EF6PrecompiledViews.xml”;
    InteractiveViews.SetViewCacheFactory(this, new FileViewCacheFactory(precompiledViewsFilePath));
    _isPreGeneratedViewCacheSet = true;
    }

    When I first run the application, SetViewCacheFactory() takes around 20 seconds and I can see the EF6PrecompiledViews.xml is generated.

    When I run the application again, SetViewCacheFactor() still takes around 20 seconds. EF6PrecompiledViews.xml is NOT regenerated so I assume it recognized it, however EF6 still seems to go through the view generation process, so I get no benefit.

    I am using EF6.1.1 in .NET 4.5.1, Visual Studio 2013.

    Any ideas? This tool is ideal for our project… if we can just get it to work!

    -Brndan

    Like

    1. Is the contents of the xml file updated between the runs? Do you change your model between the runs? If the answer to both of these questions is no – how big/complicated is your model? It may be that it isn’t view generation that is taking all the time but building the model. Try using the latest version of EF if you are not already using it – I believe there were some improvements in this area.

      Thanks,
      Pawel

      Like

      1. Thanks for the quick response.

        The hash value & XML content are identical and no models have changed. The model is quite large generating an XML file of 1.2MB with ~250 entities. We are on EF 6.1.1 which is currently the latest.

        I wouldn’t expect this to take a full 20 seconds to load up on my i7 machine….??

        For what it’s worth, I also tried the EF Power Tools view generation which likewise showed gave no improvement in startup performance.

        Like

        1. There were quite a few people reporting problems similar to yours where the start up time was slow even if pregenerated views were used (e.g. https://entityframework.codeplex.com/workitem/1749). One way to improve the start up time is to use NGEN as described here: http://msdn.microsoft.com/en-US/data/dn582034). As far as I know metadata is also being cached a bit more aggressively but you already seem to be using EF 6.1.1 and I don’t know if there are further improvements in EF 6.1.2. There is a work item to try to persist the code first model and load it when the application starts (https://entityframework.codeplex.com/workitem/1876) but I don’t think anyone is actively working on this at this time. You may try EF 6.1.2 and if it does not help you could probably file a bug on https://entityframework.codeplex.com/

          Thanks,
          Pawel

          Like

  12. I use .net 4.5 and ef 6.1.2. I use edmx file (Database First).

    I have initialized the interactive views at the begin of service as below.

    InteractiveViews.SetViewCacheFactory(dbContext, new FileViewCacheFactory(@”C:\MyViews.xml”));

    The file is created. There is no bug. All tables and views are there.

    But i cant get any performance gain?

    the compiled query does not exist for dbcontext and for the first time for a query I still wait for expression building. EF6 auto compile it. But what i think is:

    If a hash key is created for a linq to entities expression, and the compiled query is auto compiled and saved to memory with that hash by EF6, so your InteractiveViews should write it to the file that I have setup. But in that file i have only tables and views declaration.

    Am I missing something?

    Like

    1. View generation and query compilation are two separate things. View generation is a process of presenting the database as a set of database agnostic (ESQL) queries (called views). (If you are really interested how it works you can take a look at this paper: http://www.cse.buffalo.edu/~mpetropo/CSE736-SP10/pubs/p461-melnik.pdf) Query compilation is turning a Linq Query/ESQL to SQL. Queries in EF are built based on views where DbSets are represented by (query) views. In later versions of EF (I think starting from EF5) ESQL was internally replaced with DbExpression trees and ESQL is only used as a serialization format. You can think of a query view as kind of IQueryable or a root you build the query on. If you don’t use pre-generated views view generation will happen when the first query is executed. It happens only once per AppDomain. Before EF6 view generation could take a significant amount of time (read: mminutes) even for medium-sized models. There were some major performance improvements to view generation in EF6+ and now, in many cases, there is no noticeable difference in start up time whether you use or don’t use pregenerated views.
      So, query compilation depends on view generation (or to be more specific on existence of views) but is not part of view generation (btw. since view generation happens only once, possibly even before any query is sent to the database) how could it know all the queries you are using in your app?). If query compilation takes a long time I would recommend taking a look at the query – if it is very complicated maybe it is better to break it up to two or more queries – yes it would be another trip to the database but maybe it’s worth it if it is faster?

      Thanks,
      Pawel

      Like

  13. In my case;

    * i have 6 tables inner joined
    * 21 tables left joined. S
    * 30 filter parameters.
    * some parameters cause a subquery addition with exists check (this caouse recompilation)
    * some filter parameters added after query prepare with an if (x = y) { query = quary.where(….) }

    The generated sql work in less than a second.

    So for the first time i wait for 15 seconds for building the expression.

    What i think: as an asnwer of your question.

    q: how could it know all the queries you are using in your app?

    a: it dont need to know but when an expression created and tolist is called.
    EF or you can;
    * build and hash for that expression (not including filter params) and save the dbExpression to the file
    * load it at app startup.
    * when the routine is met again create the hast from linq and seek if dbExpression is in memory. And if exists use it.

    So the dbExpression will be ready so i wont loose 15 seconds again.

    BTW, how can a memory operation can be slow as 15 seconds or more for just building an expression with setting no tracking true. I dont know what is the real problem of EF.

    Like

    1. 21 left joins and 6 inner joins feels like a lot. Either the hierarchy being used is quite big or you have a lot of .Includes. If this is a lot of .Includes you possibly could split your Linq query to two or more queries and EF should fix up relationships for you. Alternatively you could try using stored procedures/TVFs to avoid the overhead. You can consider filing a bug (https://entityframework.codeplex.com/WorkItem/Create) and someone from the EF team should take a look at what happens and maybe recommend a workaround.
      As I said before – view generation is separate from query compilation and happens only once before any query is being executed. Once this is done the code is never ever called again so it is impossible to add support for what you asking for as part of view generation. Maybe it is possible to achieve with IDbCommandTree interceptor but I am not sure how easy (or, rather, how hard) it is.
      The query pipeline in EF (up to but not including version 7) is quite (overly?) complicated and touching it always results in breaking people (like this issue in the latest version). There have been quite bit improvements to query compilation but the generated queries are still far from perfect as well as it the time to generate some of the queries. AFAIK the entire query pipeline is going to be rewritten and simplified in EF7 and therefore should be faster.

      Thanks,
      Pawel

      Like

      1. Thank you for your considerations. We have merged all where statements as we do in sql stored procedures. So it only compiles and cache the query for once. Yes we wait for the first time. To ignore that at application start, we just call the query (for most important ones) with a -1 filter parameter to be compiled. And we dont want to create procedure. It sound like old days :). We have a business layer.

        I hope they will do better in EF7.

        Thanks in Advanced.

        Like

    2. gencerinc, we ran into performance problems with complex queries with many includes, especially those bring in deep many to many’s etc. When we examined the SQL generated we found it often measured in the megabytes.

      This is a terrible waste of effort for EF and SQL and is likely where the performance is being lost.

      Our solution was to break up the query into batches of includes which individually were relatively small. EF (if you have not disabled tracking) will automatically wire up the new entities you bring in from subsequent queries. In some cases we simplified our filter criteria drastically with some minor redundant data being loaded in

      I concluded from all this that EF6 is not well designed for highly complex queries with 10+ includes. Sometimes LINQ-to-entities just can’t do as good a job as a custom SQL job. Therefore you may need to introduce views or stored procedures to make it performant.

      Like

      1. From my experience manually creating SQL queries that join more than 5 tables is a smell. It might be sometimes unavoidable but typically such queries are very hard to comprehend, write or change and indicate bigger problems. EF makes it easy to create queries like this since when using .Include the complexity is hiding in the model and not in the query. On top of that EF will add (sometimes unnecessarily) additional joins. Oftentimes using many .Includes results in bringing the entire database to the app (note that EF does not support filtering on .Include) and the question is: are all these results really being used? And if so, how (e.g. if the results are shown to the user it might be very hard for them to process all the data)?
        With complex hierarchies and many .Includes EF can generate really huge and horrible queries. With regards to quality of generated SQL I don’t think any ORM can currently compete with targeted queries created by a highly skilled DBA (especially in more complicated cases). But there is also the other side of the coin – many shops don’t have highly skilled DBAs (or don’t have a DBA at all) and with an ORM an average developer can create quite complicated (even though far from optimal) queries which they otherwise would not be able to write or it would take them a lot of time and would require a lot of effort.

        Thanks,
        Pawel

        Like

  14. Hi, there.

    I use .Net 4.5 and EF 6.1.3 but i can’t get it working.
    I installed the nuget package and inserted the setupcode in my startup function.
    When using the debugger. The SetVewCacheFactory takes around 6 seconds to execute (about the same as normally the first query).
    But the file isn’t created. At the next startup the startuo times are the same.
    I’m a missing something?

    Like

    1. I am not sure why it does not work for you – are you sure you use the one that saves views to a file and not to the database? On the other hand I wonder if this is the view generation or the model building that takes the 6 secs you mentioned. SetViewCacheFactory does not generate views or send queries to the database but it accesses the underlying ObjectContext for the given DbContext instance which forces model building. So if it takes 6 secs to set the cache factory I would think you are dealing with performance issues when building the model and not when generating views. I would recommend that you profile your app and first find where the issue really is than try to address it.

      Thanks,
      Pawel

      Like

  15. Hello Pawel thank you for your tool; two questions : where is the best place to place the code, I think it is good in the DBContext constructor ?

    I had to use a method to make sure is not called more than once otherwise an exception is returned.

    public partial class xx : DbContext
    {
    public xx()
    : base(“name=yy”)
    {
    if (!zz.IsAttached(this))
    {
    zz.AttachLocal(this);
    }
    }

    ….
    }

    where

    public static bool IsAttached(DbContext context)
    {
    var oCtx = ((IObjectContextAdapter)context).ObjectContext;
    var viewCache = (StorageMappingItemCollection)oCtx.MetadataWorkspace.GetItemCollection(DataSpace.CSSpace);
    return (viewCache.MappingViewCacheFactory is SqlServerViewCacheFactory || viewCache.MappingViewCacheFactory is FileViewCacheFactory);

    }

    and

    public static void AttachLocal(DbContext context)
    {
    InteractiveViews.SetViewCacheFactory(context,new FileViewCacheFactory(String.Format(“{0}{1}{2}”, AppDomain.CurrentDomain.BaseDirectory, context.Database.Connection.Database, “.xml”)));
    }

    and second question how to make sure EF REALLY uses the cache when you send any query after? the file was generated for caching the views but how can you make sure that the file is used ?

    Thank you very much for giving us if possible a tutorial for the BEST way of calling the code (Best practice for using your tool in any application)

    Like

    1. DbContext ctor is not a good place to register view cache – view cache needs to be registered only once and you would do this over and over again if it was in the ctor. Do it somewhere else – somewhere where you initialize your app. For instance if I wrote a console app I would put in the Main function before it invokes the actual application logic.
      If you delete the file with views and it gets recreated it means that views are used. If you need a more tangible thing you would have to compile EF and EF Interactive Views in Debug configuration and set a breakpoint. If you’re asking because you don’t see too much difference in startup performance then the issue probably is not with view generation but with model building. View generation has been significantly improved in EF6 and is no longer a problem for small to mid-sized models.

      Thanks,
      Pawel

      Like

      1. Thank you Pawel, what happens is when I test with ASP.NET on IIS when I recycle the app pool, the first time it takes a while, then after each time I use DbContext it is very fast all the time and queries also. BUT If the application is not used for a while, or if I restart the app pool, DbContext is slow again on the very first launch. Also the file is not updated… So is it normal? It seems that even if the file is created, if you reset the app pool, it is not used?

        Is there a way to improve the model building? You mentionned it.

        Thanks again !
        Nicolas

        Like

        1. The file is not getting updated if the model has not changed. You can use Procmon to see if the file is being accessed. What is happening is that the file contains model hash and if the model has the same hash views don’t need to be updated but just read from the file – this is also the whole idea of pre-generated views. I actually think that views are not your problem – in EF6 view generation was actually greatly improved. It is now model building that might be causing slow start. For more details you may want to take a look at performance considerations https://msdn.microsoft.com/en-us/data/hh949853.aspx. This http://blogs.msdn.com/b/adonet/archive/2013/10/31/ef6-performance-issues.aspx might also be helpful.

          Thanks,
          Pawel

          Like

  16. hi,
    i am using ef 6.1.3 in a database first asp.net webform application .

    i create my DBContext this way :

    using (FBEntities c = ContextFactory.ObtainContext())
    {
    // working with entities
    }

    and the obtaincontaincontext code

    public static FBEntities ObtainContext()
    {

    // some code i really need here
    FBEntities context = null;
    string p ; // the connectionstring is built dynamically
    context = new FBEntities(p);
    return context;
    }

    how can i use the interactiveview with this setup plase since i may call ContextFactory.ObtainContext() several times in my web app

    thanks and good day

    ps : since you are the creator of the powertools too, i may ask this too 🙂
    i have an E_INVALIDARGS HRESULT exception :with firebird , but not with ms sql server .
    any hints please ?

    Like

    1. How big is your model? I am asking since I suspect that using pre-generated views may not result in any noticeable difference in your case. View generation in EF 6.x has been dramatically improved and using pre-generated views makes sense only for really big models. I’d recommend prototyping and measuring the difference between using and not using pre-generated views and only use pre-generated views if it the difference is significant.

      How you create the context does not matter. What matters is that you register interactive views before you send the first query to the database.

      I am not the creator of Power Tools. I moved most of the functionality of Power Tools to the EF Designer. Anyway, it’s impossible to answer your question because you have not even told what operation you were trying to do. To be honest I have never tried EF with firebird. You may want to ask Jiri (http://blog.cincura.net/) who I believe created the EF Provider for Firebird.

      Thanks,
      Pawel

      Like

      1. yes sorry for the lack of informations ,

        i have just a 10 entities in my model,
        and the first query to the database is really slow , about 6 /7 sec
        second query is instantaneous

        so if pregenerating views in my case would not help, do you have any trick i can do to improve first query execution time please?

        from what i have read these would help :
        – compiled queries
        – NGEN

        what do you think ?

        Like

        1. I don’t believe pre-generated views can help in your case. Your model is so small that you probably wouldn’t have seen any difference even when using EF4/EF5 and as I said view generation is much faster in EF6 (I would say at least an order of magnitude faster).
          The “trick” in this case is to profile the application to understand where the bottleneck is. EF is talking to the database before sending the first query and this can be the issue. Or maybe you create a database each time your app starts? Or maybe it’s not EF at all? I would say measure and then try to find a fix.

          Thanks,
          Pawel

          Like

          1. hmm you were right , i tested my query in a console application, and it took oly about 1 sec first time and no time after that, model initialization took 0.06 sec :p .

            so i have to figure out what else is wrong in my app.
            thanks for pointing me to the right path .

            Like

  17. Hi,
    I have a solution with an EF model project and two more projects, two ASP.NET applications which both use the same model and database. I used InteractiveViews at the starting point of the first application, storing the generated xml in the application startup path (where the Web.config is). I saw real improvement!
    Now, if I try to use it fot the second application and try to save the xml under the second application’s startup path, I get an error “MappingViewCacheFactory is already set”. As if it knows that the views have been generated in a different directory ! How is that?
    Thanks,
    Alex

    Like

    1. This is probably because you are trying to hook the view cache factory too late. If EF needs views before you registered view cache factory it will register the default one and generate views. Views are generated only once for an app domain so hooking a view cache factory after views have been generated doesn’t make sense and therefore EF throws. You may also want to take a look at this issue: http://efinteractiveviews.codeplex.com/workitem/1 which discuses it.

      Thanks,
      Pawel

      Like

  18. Hi,

    I have been fighting this for a couple of days now. I am using Structure Map for dependency injection, and I am using a repository that implements DbContext. I have the following code in my application start

    using(var ctx = (DbContext)nestedContainer.GetInstance())
    {
    InteractiveViews.SetViewCacheFactory(ctx, new
    FileViewCacheFactory(@”C:\MyViews.xml”));
    }

    But the file never gets created.

    I downloaded the source code, upgraded the project to .NET 4.5.1 and EF 6.2 (the levels my repository are using) and was able to step into Interactive Views. In SetViewCacheFactory() I see storageMappingItemCollection getting added to _mappingItemCollectionLookUp, but I never see a call to ViewCacheFactoryBase.Create().

    Any idea what I might be doing wrong?

    Thanks,
    Dave

    Like

    1. Likely the call happens to late. If you set a factory after doing any operation on the DB, EF already generated views because it needed them for the operation so setting the factory has no effect as it cannot help anything at this point. As explained in the blogpost a good place of setting the factory can be in a static ctor. Another places could be your Main method or Application_OnStart.

      Pawel

      Like

      1. Hey Pawel,

        Thanks for the quick response.

        I’m working in WebAPI. I have placed the code in PrePostAppStartShutdown.Start(), which is called before the global.asax. I don’t see how I can get any earlier in the pipeline than that.

        My application contains several repositories that inherit from DbContext, and I am only calling InteractiveViews.SetViewCacheFactory() on one of them, just to try to get it to work. I believe the DbContext on which I am setting the Cache Factory is the first repository that actually hits the DB (although it may not be the first one that is instantiated). Could that make a difference?

        Thanks,
        Dave

        Like

        1. Hi Dave,

          Hard to tell why the factory is not invoked. The only cases I can think of are if the factory is registered to late or (e.g. due to a bug) not at all. If you feel adventurous you clone the EF6 repo, compile the code yourself and set a breakpoint in EF to see when EF is looking for the factory.
          Before you do that however – are you sure you are going to see any improvement from pre-generating views? I know that view generation was significantly improved in 6.1.x releases and pre-generating views was no longer an issue for small and medium databases. If your database is big enough that pre-generating views actually make a visible start up time improvement you might want to use the T4 template (https://marketplace.visualstudio.com/items?itemName=PawelKadluczka-MSFT.EF6CodeFirstViewGenerationT4TemplateforC) which generates views at compile/design time. You can find more details in this post: https://blog.3d-logic.com/2012/10/17/entity-framework-6-and-pre-generated-views/

          Thanks,
          Pawel

          Like

          1. No, I’m not sure pregenerating views will help. I have made other changes that have significantly sped up the start time of my web API. I’m going to get what I have into production. Performance may be good enough where it is now.

            Thanks for your help.

            Dave

            Like

  19. while using EFInteractiveViews, contaxt is assinged to InteractiveViews.SetViewCacheFactory in using block, but in my code db contaxt is created like this MyDbContext db = new MyDbContext(); at top of controller, how can i implement InteractiveViews. thanks

    Like

    1. I would measure first if you really need pre-generated views. My rule of thumb was that with the last few versions of EF6 if the database had fewer than 100 tables I would not bother – you would likely not see any noticeable difference in startup times. If you still decide you need this you should put this in a place that runs before any code that needs EF – e.g. in Application_Start.

      Pawel

      Like

  20. Hi. I am using your interactive view in an application simply because a projection query in ef takes the whole time in the world to run the first time it is queried. But the generated view file does not contain the query produced by this projection. I can only see queries meant for DbContext DbSets in the xml file. So every time I run the app, the same same long time is spent in building the particular query.

    Does InteractiveView not support custom queries?

    Like

    1. It seems from your description that the problem is not with view compilation but with query compilation and these are two different things. View compilation prepares models that EF uses for abstracting the database. It used to be very slow but was improved greatly in latest EF6 releases. Query compilation is compiling specific queries to Sql statements. Query compilation tend to be expensive for complicated queries or when inheritance strategies are involved. (My rule of thumb is to check the SQL statement generated for the query and see how big/complicated it is). You only see the slowness the first time because EF caches compiled queries. Unfortunately, I don’t think there is an easy solution for your case. If you can, try simplifying the query. If the complexity is caused by using an inheritance strategy you could try removing inheritance from your model. This can be hard because it will likely impact the design of the application. You could try replacing the query with a Store Procedure but, again, if you are using inheritance you may not be able to because AFAIK tables contain some magic columns only EF understands and know how to handle.

      Hope this helps a little bit.
      Pawel

      Like

Leave a comment