Using EF Core in a Separate Class Library project

.net is a free cross-platform, open source developer platform to help software developers develop different types of applications. Using .net provides developers the ability to use a variety of different languages, editors and libraries to develop applicationsfd for web, mobile, desktop, gaming and IoT.

Entity Framework Core is an Object Relational Mapper (ORM) for .net Core projects, supported by Microsoft, enabling developers to work with data using objects of domain specific classes without focusing on the underlying database tables and columns where the data is stored. Using Entity Framework developers work at a higher level of abstraction which helps to create and maintain data oriented applications with less code and without having to work directly within in the Database platform.

Entity Framework Features

  • Cross-platform: EF Core is a cross-platform framework which can run on Windows, Linux and Mac
  • Modelling: Entity Framework creates POCO (Plain Old CLR Object) entities using get/set properties of different data types.
  • Change Tracking: tracks of changes occurred to instances of entities (Property values) which need to be submitted to the database.
  • Concurrency: Optimistic Concurrency by default to protect overwriting changes made by another user since data was fetched from the database.
  • Transactions: automatic transaction management while querying or saving data, with options to further customise transaction management.
  • Caching: First level of caching out of the box. Repeated querys will return data from the cache instead of hitting the database
  • Configurations: Configure EF model by using data annotation attributes or Fluent API to override default conventions.
  • Migrations: Set of migration commands that can be executed on the NuGet Package Manager Console or the Command Line Interface to create or manage underlying database Schema.

In this post we will walk you through the process of running creating a simple EF Core Database, with Migrations with Entity Model and Database Contexts in separate class libraries in a .net core Web Api project.

The Web API itself will be responsible for maintaining a list of known Referrer Spammers.

Stop Web Crawlers update API
https://github.com/threenine/swcApi
14 forks.
39 stars.
0 open issues.
Recent commits:

Often developers will aim to ensure their Database layer is entirely separate from business logic. In a lot of cases, they will also like to have their Database Entities and Domain entities as separate entities preferring to Map between these and only use Domain entities in the within their business logic.

Using an ORM, you should ensure to make your model objects as simple as possible. Be more vigilant about simplicity to make sure your model objects really are just Plain Old Data Objects (PODO), otherwise you may end up wrestling with your ORM to make sure the persistence works like you expect it to, and it’s not looking for methods and properties that aren’t actually there.

The Benefits of using ORM’s include:

  • Facilitates implementing domain model pattern.
  • A huge reduction in code.
  • Takes care of vendor-specific code by itself.
  • Cache Management – Entities are cached in memory thereby reducing the load on the DB.

To further abstract your Database logic from your business logic you may want to implement what is known as the Generic Repository Pattern and a Service Layer pattern this will usually help to ensure that no database logic or interference bleeds into the business logic of your application.

Create 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. Eventually for this particular project, we are going to create Database context for three of the main database providers. i.e. Postgres, Mysql and MS SQL.

We will mainly be dealing with the PostgreSQL context in this article. The primary reason why we will be creating separate projects for each of the anticipated contexts, is that there are a number of quirks of each Relational Database system that will need to catered for in each of the different contexts.

Although it is true, that EF core in theory enables you to connect and interact with many different data sources, you still need to cater for the slight quirks of the different databases within the DbContexts. I will walk-through some of these within this article.

Shell

Rename the generated class to SwcContext.cs

We’ll also add a reference to Microsoft.EntityFrameworkCore. In the terminal window you can use:

Shell

In the case and purpose we going to use PostgreSQL as database server.

So let’s go ahead and add a reference to those packages too.

Shell

We can now create a barebones Database Context.

C#

Database Entities

We’ll now create a new project which we’ll use to create a Database Entity objects we’ll call it rather unimaginatively Api.Database.Entity. The primary reason why we will be creating this as a totally separate project is to enable the referencing of entities across our various projects and Context Projects.

For the sake of example, We’ll create 3 additional classes:

  • Status.cs
  • Threat.cs
  • ThreatType.cs
C#

How to create a Database Context

DbContext is an important class in Entity Framework API. It is a bridge between your domain or entity classes and the database.

  • The primary class that is responsible for interacting with data as objects DbContext.
  • DbContext APIs simplify your application interaction with the database.
  • Reduces the number of methods and properties required to access commonly used tasks.

The Entity Framework API’s are not released as part of the .net core framework and an additional step if required to install them locally on your machine, if you would like to use them for either Code-First or Database-First Development. To install the EF Core APi’s globally – you can use them across any project -simply execute the following command in your terminal window:

Shell

We are now ready to edit our previously created SwcContext.cs and class library project to include a reference to our Api.Database.Entity project.

C#

How to define Entity Configuration

Earlier in this post, I pointed out that I prefer to keep my entities as simple POCO classes and I don’t use the Component Annotations to define the database properties. My preference for this is to make use of IEntityTypeConfiguration, this is based on ensuring the  Separation of Concerns principle and decoupling the persistence layer from the domain model logic. Principles defined in Eric Evans Domain-Driven Design: Tackling Complexity in the Heart of Software

IEntityTypeConfiguration enables configuration for an entity type to be factored into a separate class, rather than in-line in OnModelCreating. Implement this interface, applying configuration for the entity in the Configure method, and then apply the configuration to the model using ApplyConfiguration<TEntity>T in OnModelCreating.

C#

Information

To find out how to implement a UUID and autogeneration for ID columns in PostgreSQL check out How to generate PostgreSQL UUID with EF Core

Once we have finished creating all our Entity Type Configuration classes we just need to update our SwcContext to use use them.

C#

How to Define Migrations Assembly

The default behaviour of EF core is to place the Migration script with the assembly that defines the DbContext.

If you want to change the default behaviour, to say place the migrations script within your Web Application or API project, then you can make use of the DbContextOptionsBuilder and the new MigrationsAssembly method which you can pass the name of the assembly which you would like to include the Migrations in.

You define this by adding options when add the context configuriton during the ConfigureServices in your application Startup.cs

Advice

If you don’t define a Migrations Assembly, EF will default to placing the migrations code to the library where the repository is defined.

If you want to have your separate library to contain the migrations, then there is no need to define a migrations library. However, if you want your API or web project to contain the migration code, then you need to configure the migrations library.

This is up to your or your organisations best practice guidelines.

In this post, I will just provide instructions on how to make use of the MigrationsAssembly feature.

For my particular project, I am not going to do this, because I would like to keep all my database specific code within my database project.

How to create a DbContextFactory

We now need to create factory class for creating derived DbContext instances. This class will Implement the IDesignTimeDbContextFactory interface to enable design-time services for context types that do not have a public default constructor.

At design-time, derived DbContext instances can be created in order to enable specific design-time experiences such as model rendering, DDL generation etc.

Design-time services will auto-discover implementations of this interface that are in the same assembly as the derived DbContext type.

The ContextFactory is an implementation and example of the Factory Design pattern that is fairly common within the .net core framework code base.

Design Patterns Elements of Reusable Object-Oriented Software

Erich Gamma, Richard Helm , Ralph Johnson, John Vlissides, Grady Booch

Four top-notch designers present a catalog of simple and succinct solutions to commonly occurring design problems.

Buy Now Read Review

In order to implement this factory we will need to add and additional class to our project and call it SwcContextFactory.cs

C#

Information

In order to quickly complete an MVP version of this article you will notice I created an appsettings configuration file and quickly imported into the project. This will do for this stage and I will further be elaborating on how we use this in forthcoming articles.

To gain a better understanding of the configuration API you may want to check out my article
How to use Configuration API in .net core console application

How to create Entity Framework Core Migration

Once this is done you can now, as in my case I tend to the terminal window in Rider : cross platform .net IDE , to navigate to my project directory and simply use:

Shell

For the curious, who want to take a look and examine the SQL Scripts that will be generated to create the migrations you can use

Shell

To view the SQL script your Migrations will use for your specific Database environment.

Check out the full list of Migration Commands

Open a Terminal window and navigate to the folder containing Api.Database.Postgre.csproj i.e. cd Api.Database.Postgre. Due to the fact that we have created a Api.Database.Postgre as Class library project we will not be able to execute our dotnet ef commands directly against it, we will have to use the API as the startup project. Notice the --startup-project provided using the directory path to the API project.

Shell

Advice

If you’re using Visual Studio Code you can use the Integrated Terminal Window, or in I like to use Whack Whack Terminal – a terminal emulator for Visual Studio 2017, so you can click on the project then use ctrl + & ctrl + to open a terminal window.

After this command has completed you will notice a new folder has been created in your Database project, which will contain the migration scripts, however these scripts have not been applied to your database yet.

We can execute these scripts against our database to create database. Using the following command

Shell

We can open our Database in whichever client we prefer. I use Jetbrains Rider which has a Database viewer and installed the PostgreSQL driver. I can then simply connect to my database and navigate to it to view

Summary

Using the above technique you can encapsulate all your database logic within a separate 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.

Latest posts by Gary Woodfine (see all)