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:
- Have a defined database: We start from a defined database
- Scaffold: Use the command to generate entities and the DbContext
- 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,
Option | Brief Description |
---|---|
--output-dir | Folder where the entity classes are generated. |
--context-dir | Folder where the DbContext class is stored. |
--context | Custom name for the DbContext . |
--schemas | Specific schemas to include. |
--tables | Specific tables to include in the model. |
--data-annotations | Use attributes instead of Fluent API. |
--no-onconfiguring | Skip the configuration of the connection string. |
--no-pluralize | Keeps the original names without pluralizing. |
--force | Overwrites existing files. |
--use-database-names | Uses the exact names of tables and columns from the database. |
--no-build | Does not compile the project before the scaffold. |
--help | Displays 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.