DotNetCore

Using EF Core in a Separate Class Library project





Entity Framework Core is an Object Relational Mapper (ORM) for ASP.net Core projects. It’s. really easy to use and you can get up and running with it really quickly.

That being said it does have some quirks and idiosyncracies which may catch you off guard if you’re not aware of them. I have found keeping an eye on Julie Lermans blog really helps, she seems to have a knack for find ing the edge cases and solutions when it comes to Entity Framework in general.

In the particular example I want to highlight in this blog post, is something I uncovered when developing my series of blogs post, regarding developing an ASP.net Core API for my Stop Web Crawlers WordPress Plugin.

I wanted to keep my Database layer was seperate from API logic, in that I didn’t really want to include my Database Enity classes etc within my API code. Potentially I will be developing a further two micro service type API’s which may use the same Database Schema but not necessarily the same database server.
 

Can’t wait to see it in action ?

Check out the code on GitHub

 

Add Database Class Library Project

We make use of solution and projects files in the source code, so if you are not familiar with working with solution files using .net core you may want to check out my post – Creating and Editing Solutions files with .net core CLI.

I’ll add a new class library project, primary purpose of this project is to create Database Context object which well share across a couple of projects.

Rename the generated class to ApiContext.cs

We’ll also add a reference to Microsoft.EntityFrameworkCore We’ll also add some code to create a barebones Database Context

Database Entities

We’ll now create a new project which we’ll use to create a Database Entity objects we’ll call it rather unimaginetively Api.Database.Entity.

The default class created via the project template we’ll rename to BaseEntity.cs and we’ll add some basic entity properties we need.

We’ll also add an additional folder to the Entity Project and call it Threats. We’ll also create 3 additional classes Status.cs , Threat.cs, ThreatType.cs. To View the properties of the file check the source code repository



Add Reference to Entity

We now need to add a reference for our Entity Project project to the Database Project.

Create Portal Core Library

For the purpose of my project I will create another separate class library project, which I will call Portal.Core, the purpose of the this library will be to central library for common functions, Modules or Global variables etc required across the multiple projects.

We’ll rename the generated class to SchemaName.cs and we will add constant string value of Portal

We need to add 2 new Addtional Nuget Packages to the Api.Database.csproj

  • Microsoft.EntityFrameworkCore.Design
  • Microsoft.EntityFrameworkCore.Tools.DotNet

We are now ready to update, ApiContext.cs with additional logic

Our EF Core work is now complete. We have a basic Schema, and we have developed our Context, for the most part we are done. All we need to do now is create the Migration to get our Database up and running.

I will illustrate how we will make use of SQL Server 2016, running within a Docker Container to enable testing of the Migration Scripts. I won’t discuss how to get started with SQL Server and Docker. Microsoft do a pretty good job of explaining Connect to SQL Server on Linux



Once you have your SQL Server up and running whichever way you choose. We will need to create another DummyUI console project. The reason for this is a little quirk in how EF Core works, is that you are unable run Migrations against Class Library projects. We will create a Dummy Console Poject, that will be used as the Start Up project for the Migration task.

We will need to add a couple of references to the DummyDB

  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.Design
  • Microsoft.EntityFrameworkCore.Tools.DotNet

We also need to add project references to our Api.Database & Api.Database.Entity

We need to add an Additional class to our Api.Database pjoject

 

The process of creating a Migration is as follows:

Open the Terminal and navigate to the folder containing Api.Database.csproj
so right clicking on the project and Selecting Open Command line

Then using dotnet ef --startup-project ../DummyDB migrations add [Migration Name]

will initiate the migrations
When setting up an EF Core project ensure the the CSproj file has the following references

Add reference the EF Library

In order to make use of our seperate library we will need to edit the StartUp.cs to add our Context to the Services Collection.

In my case I am making use of Microsoft SQL Server, so I will also need to add Nuget Package Microsoft.EntityFrameworkCore.SqlServer and Microsoft.EntityFrameworkCore.SqlServer.Design to the Api Project.

Summary

Using the above technique you can encapsulate all your database logic within a seperate class library project that you can share across multiple projects. You will not be dependent on any project to build or execute any database changes, the result being all your database activities are encapsulated and constrained to one library.

To expand further on this example, you may want to read How to seed your EF Core Database, to find out how you can further isolate and manage your database concerns usings EF Core.

Gary Woodfine

Freelance Full Stack Developer at threenine.co.uk
Helps businesses by improving their technical proficiencies and eliminating waste from the software development pipelines.

A unique background as business owner, marketing, software development and business development ensures that he can offer the optimum business consultancy services across a wide spectrum of business challenges.

Latest posts by Gary Woodfine (see all)

  • Jonathan Nungaray

    Thanks for the post! but How can we integrate this with the api project?

    • Jonathan, thank you for question.
      I now realise this may be glaring omission from my post. I will update it shortly.

      Essentially it is the same way you would using standard EF, you add a reference and Inject the Context.
      I will provide details in the update.

      • Jonathan Nungaray

        Yes thanks!, I already did it, was a little tricky since I am using simple injector instead the native one

  • Pingback: How to seed your EF Core database - Gary Woodfine()

  • manu

    Gary, Can you give me tips to do this process using EF Core Database First approach? Using Microsoft docs site, I can generate the entities only in the same folder, but not in a different project library. Needs to separate Entities and EF DB libraries. Thanks

    • Manu, I haven’t actually tried this as I am away from a .net dev enviornment but I believe you should be able to do something similar too

      Scaffold-DbContext -Connection
      “‘[your connection string]” -Provider
      “Microsoft.EntityFrameworkCore.SqlServer” -OutputDir “Models” -Context
      “DbContext” –verbose

      Remember just to navigate to your project folder. If I have time this week, I may write a blog post explaining and a sample.
      Hope tthis Helps

      • manu

        Thanks for the suggestion. I tried with -Project option which will generate entities in a different project and -OutputDir option which will generate in a different folder, and both are working. However, I face difficulty in trying to add BaseEntity class inheritance reference while generating these new classes. I would like these models to avoid reference to EF namespace references and should be just POCO objects.

  • Chris Hogan

    Great article. Only problem is I am trying to do the same thing, but do it using database first but no matter what i try I am getting the message.

    System.IO.FileNotFoundException: Could not load file or assembly ‘Microsoft.EntityFrameworkCore.Design, Culture=neutral, PublicKeyToken=null’. The system cannot find the file specified.

    The refernce is showing as valid but database first code generation is not working.

    • Chris,
      Just check to ensure that you have the right references added. Microsoft.EntityFrameworkCore.SqlServer.Design needs to be added to the via nuget.
      You should be all set then. If you have a Git Repo I can help setting up your project.

      • Chris Hogan

        I had been following another walk through. It had me pull in multiple other dependencies. I started a new project and only added the following.
        Microsoft.EntityFrameworkCore.SqlServer
        Microsoft.EntityFrameworkCore.SqlServer.Design
        Microsoft.EntityFrameworkCore.Tools

        They added without error, so it appears that I was having a dependency collision of some sort. I have sense been able to build my database context against my current schema.

  • Tom Donino

    Any specific reason you used ModelBuilder instead of DbModelBuilder in OnModelCreating method? Is that something different in Asp.Net Core 2?

    I am building my own custom Web App Template so the template will only access User identity Db; so I am having AppContext inherit from IdentityDbContext

    • I think DBModelBuilder is just the ASP.net core 2 implementation of ModelBuiler. The code I have was developed using core 1.0/1.1 so it is possible they may have renamed it for 2.0 . I haven’t been doing any EFCore work lately so no fully up to speed

    • Just looked into this DBModelBuilder is a EF6 feature.

      There are a number of differences between EF Core and EF6, so DBModelBuilder provided a bit more control over caching in EF6. Which I think they may have completely rewritten in EF Core

  • Tom Donino

    “We will create a Dummy Console Project, that will be used as the Start Up project for the Migration task.” and how does that work when you have a web application project in the solution? You cant have the dummy project as the start up and you cant have two start ups obviously

    • You don’t need to have two start up projects. As you will read in the instruction you are using the command line switch to set your start up project to fire the migration event

      Incidentally You can have to start up projects in a solution. If you right click on your solution file select properties you can define which projects you want to start as start up projects.

  • Adelia

    Hi, is it possible not to add Microsoft.EntityFrameworkCore.SqlServer to the Web project? I want the web project not to care about what EntityFramework implementation I have in the infrastructure. Thank you.

    • You can store it in the config file.

      • Dimitar Dimitrov

        I still don’t understand. Adding this line: services.AddDbContext(options => options.UseSqlServer(Configuration.GetConnectionString(“ApiDB”))); in fact means that Main Project knows about dbcontext, which should be isolated in another layer. DB layer, and the API should not care where the data comes from..

        • And what would be the real value of that?
          In all my years of developing real world highly scalable software applications I have never needed to change the database provider of a software application.
          Introducing and implementing another layer of abstraction such as that, has no real business value, and it will almost never be implemented or required.
          If you wanted to do this, it is somewhat of a trivial matter, to do so, but it is almost of absolute zero real business value.

          • Robert Lara III

            Dimitar Dimitrov, what you are referring to is Dependency Injection, but what you are talking about is the difference in your MVC application accessing a service layer or web service layer. With your MVC application, you need the DI you are referring to in the Startup class, that is because the application needs to know what assemblies to bind. If you do not want your MVC application to know anything at all about your data source or layer, you need to make a Web API project, and have your MVC application call it. This will set things up for a SOA architecture, then you can create all kinds of application that can call your web services and they will know nothing about the data source or anything. Here is a great article for setting up restful services with ASP.Net Core 2.0 Web API, which is what I think you are looking for: https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-web-api

  • Jake Catayoc

    Just a noob question… why did you name the method that adds the Created/Modified fields AddAuitInfo()? Does the word “Auit” have some meaning of some sort, or was it supposed to be “Audit”? Please enlighten me. Thanks!

    • It’s audit pronounced in a west country accent with an invisible d 🙂

      • Jake Catayoc

        Thanks for this one! Now my next question is for the CreateDbContext() in ApiContextFactory.cs. The SQL connection there is pointed to a local db, config database. I thought it’s necessary so I left it, and while I used my own database connection string on my Api project, I ran “dotnet ef database update” on my Api project. The thing is, the tables did not create on my own database connection, and only on the config database (despite the connection string set up on my appSettings.json on my Api project.)

        So I thought of changing the ApiContextFactory.cs so that it now points the connection to my own database and tried again. Indeed, it created the migration table and all the models I created on the right database.

        My dilemma now is this– after I develop the app locally on my PC, I will have to deploy it on a Linux server, with its SQL Server instance not exposed publicly, so if I’m going to create the database manually from within an SSH shell to the server. This would mean I will have to change the connection strings, and because ApiContextFactory.cs is compiled, I cannot do that unless I change the code and recompile (which I don’t want to do.) Also, it is a Class Library, so I think it’s impossible to create a Settings file in a Class Library Project and have my database settings changed there–it has to be configured from my Api project, and run the update database using the database connection string from the Api project.

        The question now is this–is it possible for the Class Library’s ApiContextFactory to take the settings from my Api project’s connection strings settings file instead of hard-coding it within the ApiContextFactory? I’m still experimenting with several options but I am hoping I could get your recommendations.

        • I don’t understand why you put the connection string in the Database project ?
          The database connection string is defined be in the App.Settings JSON file in the API project, as in the example
          https://github.com/threenine/swcApi/blob/master/src/api/appsettings.json

          When you deploy your application just ensure you put a reference to you production database.

          • Jake Catayoc

            Yes, I did just that on the API project (on the appSettings.json), but when I tried to run “dotnet ef database update” to create the tables on the database, it didn’t do so. What happened was it followed the connection string that was ApiContextFactory.cs file. If you check your sample, there was a hard-coded connection string there. When I ran the dotnet ef database drop to supposedly delete the database, it referred to the config database connection that was hard-coded on the ApiContextFactory file, not the database connection that I defined in appSettings.json on the API project.

            So I changed the hardcoded database connection in the ApiContextFactory so it pointed on my SQL Server database, and true enough, my tables were generated on that connection.

            Did I miss something? Should I do something on the ApiContextFactory.cs file?

          • Ok couple of issues, you don’t need to run database update to create the database .

            The database is created when you run the Api project

            The line with Database.Migrate. Does this, it runs all your migrate scripts you generate with the class library project . If your database does not exist it effectively runs create scripts

          • Jake Catayoc

            Oh, I get it! Thanks again! 🙂

          • No worries. You helped me to identify some weak points in my post I will try pad out soon.
            Thanks

π