Code-First is a development approach in Entity Framework where data models are defined using C# classes.
In this model, we start from C# classes to define our data structure. These classes (which we call entities) represent the database tables, and their properties represent the columns.
Subsequently, Entity Framework takes care of automatically generating the corresponding database (including tables, relationships, and constraints) from these entities.
This approach is especially useful in new projects, where there is no predefined database, or in projects where you prefer to maintain total control over the database design through code.
This contrasts with the Database First approach, where you start from an existing database and the classes are generated automatically.
Workflow with Code-First
The workflow with Code-First consists of the following steps:
- Define the model: We create classes that represent our data (entities and DbContext).
- Relationship configuration: We configure relationships and constraints through code.
- Migrations: Generate and apply migrations to create or update the database.
- Operations: Perform operations as we would normally.
The data model
We have seen how to create the model, relationships, and operations in the rest of the course. So I won’t dwell on it too much here.
But, as a summary, suppose we have a model like this:
Entities are C# classes that represent the database tables. Each property of the class represents a column in the table.
For example, if we want to create a Products table, we define the following class:
public class Product
{
public int Id { get; set; } // Primary key
public string Name { get; set; }
public decimal Price { get; set; }
public int Stock { get; set; }
}
In this example:
Idis the primary key of the table. Entity Framework automatically recognizes properties namedIdorClassNameIdas primary keys.Name,PriceandStockare columns of the table.
The context is a class that inherits from DbContext and acts as a bridge between the entities and the database. This class contains properties of type DbSet<T>, which represent the database tables.
public class MyContext : DbContext
{
public DbSet<Product> Products { get; set; } // Represents the Products table
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// Configure the database connection
optionsBuilder.UseSqlServer("Server=myServer;Database=MyDatabase;Trusted_Connection=True;");
}
}
In this example:
Productsis aDbSetthat represents theProductstable.OnConfiguringis used to configure the database connection string.
Entity Framework allows defining relationships between entities, such as one-to-one (1:1), one-to-many (1
Suppose we want to add a relationship between Product and Category. A product belongs to a category, and a category can have many products.
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Product> Products { get; set; } // 1:N relationship
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public int Stock { get; set; }
public int CategoryId { get; set; } // Foreign key
public Category Category { get; set; } // 1:N relationship
}
In this example:
CategoryIdis the foreign key that relatesProducttoCategory.Categoryis a navigation property that allows access to the category associated with a product.
Migrations
Migrations are a mechanism that allows generating and applying changes to the database from the entities defined in the code.
Each migration is a versioned record of changes made to the application’s data model, reflecting a set of modifications to apply to the database (add or remove tables, fields, constraints, etc.)
To create a migration, we use the .NET CLI (dotnet ef).
Previously, Package Manager Console commands like Add-Migration, or Update-Database were used. They are currently deprecated, so if you see them, it’s old documentation.
Creating the first migration
To create the first migration, open a terminal in the project folder and run:
dotnet ef migrations add Inicial
This generates a Migrations/ folder with three files:
20250407123456_Initial.cs→ Class withUp()andDown()methods.SchoolContextModelSnapshot.cs→ Reflects the current state of the model.- An additional configuration file if necessary.
Apply migrations to the database
Once the migration is created, run:
dotnet ef database update
This applies the Up() instructions to the database. If there is an error, the transaction is rolled back.
EF automatically creates a __EFMigrationsHistory table where it stores which migrations have been applied. This allows applying only the new ones and avoiding duplicates.
Model changes and migrations
Suppose we add a new entity:
public class Course
{
public int Id { get; set; }
public string Title { get; set; }
public int Credits { get; set; }
}
And we add it to the DbContext:
public DbSet<Course> Courses { get; set; }
We generate the migration:
dotnet ef migrations add AgregaCurso
And then:
dotnet ef database update
EF will apply only the minimum and necessary changes. In this case, create the new Courses table.
What don’t migrations do?
- They don’t handle data. If you need to insert information, you must write additional code (for example, in
Up()). - They don’t detect some “subtle” changes, such as renaming a property (they interpret it as deletion + creation).
- They don’t synchronize data in production. In many environments, these migrations must be reviewed or applied manually.
