Quick Tip: Entity Framework Core Models In Class Library
If you are looking for a way to convert your existing Entity Framework data layer to Core 1.0, you may run into some issues. Today, I provide a workaround thanks to a fellow blogger.
Over this past months, I've been slowly converting my CMS over to ASP.NET MVC/EF/Identity Core 1.0 and implementing pieces as they become more stable.
This weekend, I was wrestling with an issue of generating Entity Framework Entities in an ASP.NET Core 1.0 Class Library.
I wanted to keep my data layer in a separate assembly because, well...you know, it's like an onion.
Thinking I could generate my new entities using the dnx ef scaffold dbcontext
technique from before, I tried it.
Just call me Mr. Optimist, but it didn't work.
I was going through everything in my head.
"Ok, do we have everything to generate the entities?"
"Am I missing an assembly?"
Check the project.json
After thinking I didn't have an assembly installed, I looked over the project.json
file to see what was missing.
project.json
{ "dependencies": { "Microsoft.NETCore.App": { "version": "1.0.0", "type": "platform" }, "Microsoft.EntityFrameworkCore.Design": "1.0.0-preview2-final", "Microsoft.EntityFrameworkCore.SqlServer": "1.0.0", "Microsoft.EntityFrameworkCore.SqlServer.Design": "1.0.0", "Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0", "Microsoft.AspNetCore.Routing.Abstractions": "1.0.0", "Microsoft.AspNetCore.Mvc.Abstractions": "1.0.0", "System.Collections.Specialized": "4.0.1", "Microsoft.AspNetCore.Mvc.ViewFeatures": "1.0.0", "System.Linq.Queryable": "4.0.1", "System.Xml.XmlDocument": "4.0.1" }, "tools": { "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final" }, "frameworks": { "netcoreapp1.0": {} } }
Nope, nothing looked weird in the project.json.
Next, Try to Generate the Entities...Again
With the project.json in good shape, I tried to generate the entities again by using the command-line in the project directory.
dotnet ef dbcontext scaffold "server=localhost;database=myDatabaseName;Trusted_Connection=true;" Microsoft.EntityFrameworkCore.SqlServer --output-dir Models/EF
After waiting for a couple of seconds, I receive this little message:
error CS5001: Program does not contain a static 'Main' method suitable for an entry point
Umm...you are correct because it's a class library, not an executable.
Ok, that didn't work.
My Last Resort: "Oh Gooooogle?"
In a last ditch effort, I kept asking Ash and Coulson what they thought. They were no help! :-p
So I decided to talk to my other best friend, Google.
After searching for 15 minutes, I found a well-written post by Ben Cull about Entity Framework Core Migrations in Class Library Projects.
It seems this is an issue with EF Migrations Core RTM and it is acknowledged as a problem. They are working on it.
Right now, there is a workaround. You need a static void Main()
in an empty Program.cs and place it into your root of the Class Library.
public class Program { // - Taken from http://benjii.me/2016/06/entity-framework-core-migrations-for-class-library-projects/ // to make EF work. // - Used this to generate EF scaffolding at the command line in the root of the project: // dotnet ef dbcontext scaffold "server=localhost;database=MyDatabaseName;Trusted_Connection=true;" Microsoft.EntityFrameworkCore.SqlServer --output-dir Models/EF public static void Main(string[] args) { } }
That Was It
Re-run your dotnet ef dbcontext scaffold
command from above at the command-line. It will recompile your code and everything should be ok.
One last thing that Ben mentions is that our fake app (the Program.cs) needs to know how to create a DbContext.
Lastly, we need to let our fake app know how to create your DbContext. The tools would normally gather this information from your startup.cs, but since that would be a huge pain to implement, let’s cheat and create an IDbContextFactory instead.
Add the following class to your class library:
public class TemporaryDbContextFactory : IDbContextFactory<PinchContext> { public PinchContext Create(DbContextFactoryOptions options) { var builder = new DbContextOptionsBuilder<PinchContext>(); builder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=pinchdb;Trusted_Connection=True;MultipleActiveResultSets=true"); return new PinchContext(builder.Options); } }
Thanks, Ben (@BenWhoLikesBeer) for getting me back on track with EF Core.