Exploring Entity Framework Core

Introduction

Welcome to our blog post, where we'll explore the two primary approaches of Entity Framework Core (EF Core): Code First and Database First. EF Core, developed by Microsoft, simplifies the process of building database applications, as we discussed in a previous post. In this article, we'll delve into the concepts of Code First and Database First, and provide examples of implementing each approach. So let's get started!

Code First Approach in Entity Framework Core

The Code First approach in EF Core involves designing and coding the model classes first, and then letting EF Core create the corresponding database or tables based on those classes.

To demonstrate this approach, let's use the same structure we explored in our previous post on Database First. You can find all the code examples on GitHub.

Implementing Code First with EF Core

First, we need to create a class for each table in our database. In this case, we'll create two entities:

public class User
{
    public int Id { get; set; }
    public string UserName { get; set; }
}

public class JobExperience
{
    public int Id { get; set; }
    public int UserId { get; set; }
    [MaxLength(50)]
    public string Name { get; set; }
    public string Details { get; set; }
    public string Environment { get; set; }
    public DateTime? StartDate { get; set; }
    public DateTime? EndDate { get; set; }
}

As you can see, you can include annotations on properties. In this case, we have set a maximum length of 50 characters for the "Name" column in the database.

Next, we install the Microsoft.EntityFrameworkCore.Design package and the MySQL package since we are using MySQL for our database. If you're using a different database like SQL Server, you'll need to install the appropriate package. Refer to the documentation for more information.

Then, we create a class that inherits from DbContext and defines the database instance and the tables it contains:

public class ExampleEFContext : DbContext
{
    public virtual DbSet<User> Users { get; set; }
    public virtual DbSet<JobExperience> JobExperiences { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseMySQL("server=127.0.0.1;port=4306;database=exampleEF;user=root;password=exampleEFpass");
    }
}

In the DbContext class, we configure the tables and the database connection. However, it is recommended to configure this in the Startup.cs file for better separation of concerns. For simplicity, we've included it here.

Once we have everything set up, we can create the database. One option is to execute the code when the program runs, ensuring that the database is created if it doesn't already exist:

using (var scope = app.Services.CreateScope())
{
    var context = scope.ServiceProvider.GetRequiredService<ExampleEFContext>();
    context.Database.EnsureCreated();
}

Now, let's take a look at the result:

Code First EF Core Execution

As you can see, the "Name" column has the specified varchar length limit of 50 characters from the annotation.

The EnsureCreated method is useful for quickly setting up the database, especially during the initial development phase of a project. However, we'll modify this code when we explore migrations in future posts.

Database First Approach in Entity Framework Core

This section covers how to use the "Database First" approach in EF Core. If you're unfamiliar with Entity Framework, it is a Microsoft framework that simplifies database application development, as we discussed in a previous post.

What is Database First?

The Database First approach means creating the database first and then generating the EF Core model (classes) based on that database. This approach is useful when you already have an existing database or when you want more control over the database structure.

Implementing Database First with EF Core

Before we proceed with the implementation, let's create the database. In this example, we'll use MySQL through Docker, but this approach works with any relational database. The only change required is the connection string in the C# code.

First, create the database and the tables. In this case, we'll create two tables with a relationship between them:

CREATE DATABASE IF NOT EXISTS `exampleEF`;
USE `exampleEF`;

CREATE TABLE IF NOT EXISTS `users` (
  `Id` int(11) NOT NULL AUTO_INCREMENT,
  `UserName` varchar(50) NOT NULL,
  PRIMARY KEY (`Id`),
  UNIQUE KEY `UserName` (`UserName`)
);

CREATE TABLE IF NOT EXISTS `jobexperiences` (
  `Id` int(11) NOT NULL AUTO_INCREMENT,
  `UserId` int(11) NOT NULL,
  `Name` varchar(150) NOT NULL,
  `Details` varchar(5000) NOT NULL,
  `Environment` varchar(500) NOT NULL,
  `StartDate` date DEFAULT NULL,
  `EndDate` date DEFAULT NULL,
  PRIMARY KEY (`Id`),
  FOREIGN KEY (`UserId`) REFERENCES `users`(`Id`)
);

Now, let's import the entities from the database using EF Core. First, install the Microsoft.EntityFrameworkCore.Design package:

dotnet add package Microsoft.EntityFrameworkCore.Design

If you're using a different database, such as MariaDB or SQL Server, the packages you need to install will be different. Refer to the documentation for the specific packages for your database.

Once the package is installed, run the following command to scaffold the entities using EF Core:

dotnet ef dbcontext scaffold "server=127.0.0.1;port=3306;database=exampleEF;user=exampleEFuser;password=exampleEFpass" MySql.EntityFrameworkCore -o Models

In the above command, replace the connection string with the appropriate one for your database. The -o Models option specifies the location where the generated classes will be placed.

After the command completes, you'll see the generated classes, including the DbContext that represents the database and a DbSet for each table.

Finally, we can improve the default implementation of EF Core. By default, the connection string is present within the DbContext, but this is not secure and will trigger a warning. We need to configure the DbContext within the dependency container, which can be done in the Startup.cs or Program.cs file, depending on your .NET version. Ideally, the connection should be stored in a configuration file or a credentials vault. Here's an example:

builder.Services.AddDbContext<ExampleEFContext>(options =>
    options.UseMySQL(builder.Configuration.GetConnectionString("exampleEF")
        ?? throw new Exception("Missing connection string")));

With this configuration, we can remove the OnConfiguring method from our DbContext.

Conclusion

In this blog post, we explored the Code First and Database First approaches in Entity Framework Core. The Code First approach allows us to design and code the model classes, while EF Core takes care of creating the corresponding database. On the other hand, the Database First approach involves creating the database first and generating the model classes from it.

Both approaches have their merits, and the choice depends on your project requirements and preferences. Whether you prefer starting with code or an existing database, Entity Framework Core provides powerful features and simplifies the development process. Stay tuned for more articles as we delve deeper into Entity Framework Core in future posts!