entity-framework-database-first

Database First in Entity Framework

  • 4 min

One of the classic approaches when working with databases and Entity Framework is the so-called Data First.

In this model, we start from an already existing database and automatically generate the corresponding C# classes that allow us to interact with it through code.

The Data First approach is suitable when there is an existing database with its tables, relationships, primary and foreign keys, and we want to work with it using EF Core.

This contrasts with the Code First approach: where we write classes in C# and EF generates the database.

Workflow with Database-First

The workflow with Database-First consists of the following steps:

  1. Have a defined database: We start from a defined database
  2. Scaffold: Use the command to generate entities and the DbContext
  3. Operations: Perform operations on the database

Basic syntax of the scaffold command

The Data First approach is mainly carried out through the scaffold command, which is responsible for reading the database and generating the necessary code.

dotnet ef dbcontext scaffold "<connection_string>" <provider> [options]
  • “connection_string”: specifies how to connect to your database (don’t forget the " quotes " )
  • provider: provider that we will use
  • options: additional options

Useful options

Some of the options we can use when using the scaffold command are,

OptionBrief Description
--output-dirFolder where the entity classes are generated.
--context-dirFolder where the DbContext class is stored.
--contextCustom name for the DbContext.
--schemasSpecific schemas to include.
--tablesSpecific tables to include in the model.
--data-annotationsUse attributes instead of Fluent API.
--no-onconfiguringSkip the configuration of the connection string.
--no-pluralizeKeeps the original names without pluralizing.
--forceOverwrites existing files.
--use-database-namesUses the exact names of tables and columns from the database.
--no-buildDoes not compile the project before the scaffold.
--helpDisplays help for the command.

Complete example of the command

Let’s see it better with a typical example of how a complete scaffold command could look like.

dotnet ef dbcontext scaffold \
"Server=localhost;Database=MyDB;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer \
--output-dir Models \
--context-dir Data \
--context CommerceContext \
--tables Clients Orders \
--no-onconfiguring \
--use-database-names \
--data-annotations \
--force
  • Generate classes only for two tables: Clients and Orders
  • With original names, in separate folders,
  • Without exposing the connection string in the code

Of course, this is just an example, and you will have to configure it to the needs of your project. But, more or less, you get the idea.

Structure of the generated code

When we execute the command, and it finishes, the result is that two things will have been generated for us.

A DbContext class that represents the connection to the database and contains a DbSet for each table:

public partial class MyDatabaseContext : DbContext
{
    public virtual DbSet<Client> Clients { get; set; }
    public virtual DbSet<Order> Orders { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("connection_string");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Here EF configures relationships, keys, etc.
    }
}

A class for each table, with its properties mapped to the columns:

public partial class Client
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
}

These classes are marked as partial, which allows us to extend them without touching the generated code, which is a good practice.

Do not directly modify the generated classes. Use partial class to extend them without losing changes when regenerating.

Re-generating the model after changes in the database

If at any time you change the database and want to regenerate the classes and first delete the previous ones, you can run the previous command again.

Alternatively, you can force the rewrite using the --force option.

dotnet ef dbcontext scaffold "connection" Microsoft.EntityFrameworkCore.SqlServer -o Models --force

The flag --force overwrites existing files.