Entity Framework 6 and pre-generated views

The version for EF6 RTM is now available.

(If you are interested in pre-generated views in EF6 take also a look at this .)

Entity Framework 6 is here. Even though it is in a very early stage it already looks exciting – a lot of improvements in Migrations (multi-tenant migrations, migrations history table customizations), Async, DI for resolving dependencies, code based configuration. Most of it (including features shipped in EF5 – e.g. enums) is running on both .NET Framework 4 and .NET Framework 4.5. In addition trying all of this is as simple as 1, 2, 3 – signed nightly builds are available on a nuget feed. We also take contributions and are thankful to everyone who has already contributed. There is one thing in EF6 that is missing however – the ability to create pre-generated views. I would love it to stay this way but unfortunately views are still one of the problematic areas in EF6. We see some promising activities around views and I hope this will help resolve or at least relieve the problem but for now the solution is still to pre-generate views. So, how do you pre-generate views in EF6? In the previous versions of EF you would either use EdmGen or EF Power Tools. Heck, you could even use my T4 templates. The problem is that all these tools are using System.Data.Entity.Design.dll to generate views and this code was not open sourced. Also, the code generated by System.Data.Entity.Design.dll will not work (without modifications) for EF6. So, it seems it is not possible to pre-generate views on EF6 then… But wait, EF6 is open source isn’t it? Why not make the code that is needed to create views public to enable view generation? It’s one option but there is also a second option – hack the system. While I strongly believe the first option is the right thing to do in the long run for now I went with the second option. There is one main reason for this – making some random functions public to make stuff work is less then ideal. It would be much better to add a nice(r), small API for view generation that could be used by tools that need to generate views. Therefore I decided to create a T4 template for generating views which, at the moment, is using reflection to get what it needs. I treat it just as a prototype (that’s one of the reasons why only C# version exists at the moment) and I hope it will help me define the right API for view generation. When I get to this point I will be able to remove the reflection hacks and just use the API. There is one more thing about the template itself. Since it is not possible to use System.Data.Entity.Design.dll the code needs to be generated by the template itself. It’s a bit more work but allows for much more flexibility. For instance, view generators based on System.Data.Entity.Design.dll were prone to the “No logical space left to create more user strings” error caused by the number of strings in the generated code that could be so big that it reached the .NET metadata format limit on the number of user string characters. This error would prevent an application from starting. This problem is now solved – the template creates an xml file that contains actual view definitions and saves this file in the assembly as an embedded resource. When the EF stack requests views the code generated by the template loads views from the embedded xml file. Using the template is not much different from using the templates for EF5 as it is too published on Visual Studio Code Gallery. First, if you have not already, setup the nuget feed containing EF6 assemblies. Create a new project and add the EF6 nuget package (make sure to select “Include Prelease” in the dropdown at the top of the window) from the feed you created. Now you can start writing your app. Once you have something that compiles right-click on your project and select Add→New Item (Ctrl+Shift+A). In the “Add New Item” window select “Online” on the left. You may want to filter by EF or EF6. Select the “EF6 CodeFirst View Generation T4 Template for C#”. Change the name of the .tt file so that it starts with the name of your context and press the “Add” button:

Once it’s done you should see the template and two new files added to your project – one of the files is the embedded xml resource file containing views and the second is the C# files used to load views from the first file:

If you need to uninstall the templates go to Tools→Extensions and Updates… select the template from the list and click the “Uninstall” button.

That’s it for now. Use EF6, enjoy the template and report bugs for both…

13 thoughts on “Entity Framework 6 and pre-generated views

  1. I tried yout Template, but it thows an InvalidCastException at the following line:
    »var configFile = project.ProjectItems.Cast().FirstOrDefault(i => string.Compare(“web.config”, i.Name, true) == 0 || string.Compare(“app.config”, i.Name, true) == 0);«

    Exception-Detail: Running transformation: System.InvalidCastException: Die angegebene Umwandlung ist ungültig.
    bei System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
    bei System.Runtime.InteropServices.CustomMarshalers.EnumeratorViewOfEnumVariant.GetEnumVariant()
    bei System.Runtime.InteropServices.CustomMarshalers.EnumeratorViewOfEnumVariant.MoveNext()
    bei System.Linq.Enumerable.d__b1`1.MoveNext()
    bei System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
    bei Microsoft.VisualStudio.TextTemplating44A6BE63B15E99CDA0B930FA4A12709B839F2FA8FBD158DEE5924763993F530900A9B62E844F7EB44E6E0FB16C2F8593FA9D872C10AC0875C02FC83F5C1CC32C.GeneratedTextTransformation.GetConfigFilePath() in c:\Dropbox\Entwicklung\Itm\Biz\BusinessObjects\ItmDbContext.Views.tt:Zeile 266.
    bei Microsoft.VisualStudio.TextTemplating44A6BE63B15E99CDA0B930FA4A12709B839F2FA8FBD158DEE5924763993F530900A9B62E844F7EB44E6E0FB16C2F8593FA9D872C10AC0875C02FC83F5C1CC32C.GeneratedTextTransformation.TransformText() in c:\Dropbox\Entwicklung\Itm\Biz\BusinessObjects\ItmDbContext.Views.tt:Zeile 38. c:\Dropbox\Entwicklung\Itm\Biz\BusinessObjects\ItmDbContext.Views.tt 266 1 BusinessObjects

    I use VS2012 and the project, where the DbContext-Devived Class is located is a Class-Library Project.

    Can you tell me, where Im going wrong?

    Thanks in advance
    Andreas

    Like

    1. I am not sure what is the root cause of the problem here (but I think I know a workaround that will prevent the exception). ProjectItems should contain only items that are of ProjectItem. That’s why I used Cast(). Apparently in your case ProjectItems contains something that is not of ProjectItem type (it would be interesting to learn what it is) and the query fails. You can rewrite this query as follows:

      ProjectItem confgFile;
      foeach(var i in project.ProjectItems)
      {
      var projectItem = i as ProjectItem;
      if (projectItem != null)
      {
      if (projectItem.Name == "web.config" || projectItem.Name == "app.config")
      {
      configFile = projectItem;
      break;
      }
      }
      }

      This should fix the exception. I have not tried using the template with the DbContext derived class in a separate assembly. Let me know if the above works for you. If not, you can provide me with a repro and I will investigate.

      Mit freundlichen Gruessen,
      Pawel

      Like

  2. Thanks a lot. You did it!
    There is only one thing. When I try to use a SQL-Server User instead of a Windows-User in the connectionString of my DbContext, there is still an error which says, that the keyword “userId” is not supportet.
    In the connectionString i use the keyword “user id” (including space), which should be right, but the error is raising as long as i use a sql-server-user-authentication.
    I hope, that my description of the problem is correct but my english is very bad (I am from Austria). Thanks in advance.
    Greets
    Andreas

    Like

    1. I don’t know if this error is related to the template. Can you show the exact error message, your config and the stack trace? Also, can you make sure that you don’t have userId anywhere in your code (findstr /sim userid *.* should do the trick)?
      Keine Sorge! Ihr Englisch ist sehr gut!

      Like

    1. I don’t think it would be too hard. Without too much thinking I believe this mostly the matter of having/not having edmx file rather than ObjectContext vs. DbContext.

      Like

  3. I’m getting error :

    “Compiling transformation: The type or namespace name ‘ContainerMappingViewGroup’ could not be found (are you missing a using directive or an assembly reference?)”

    at line:

    private void SaveViews(ContainerMappingViewGroup viewGroup)

    Entity Framework 6.0.0 RC1… And Nightly Build (4/10/2012 dated)

    Like

    1. Hi Erhan,

      There were a few bugs in EF6 RC1 that made it impossible to use pre-generated views. Therefore I decided not to post what I had on the VS Gallery. However the bugs were fixed post EF6 RC1. I did update the template but it’s not on the VS gallery yet (I will post it to the VS Gallery when/before EF6 ships). If you would like to try the latest version (it should work for nightly builds and for the upcoming EF6) you can download it from my github – https://github.com/moozzyk/EF6CodeFirstViewGenT4TemplateCSharp. Note – I am planning to change the way it interacts with the user’s context – at the moment it requires a special directive and it does not work on VS2010 and VS2012 RTM (you would have to have at least VS 2011 Update 11 to use it).

      Thanks for trying and reporting the problem though!

      Like

Leave a comment