Entity Framework Core Integration
Relevant source files
The following files were used as context for generating this wiki page:
The WEBAPI project utilizes Entity Framework Core (EF Core) as its primary Object-Relational Mapper (ORM) for data access. It employs a "code-first" approach, where the database schema is defined and managed through C# model classes and configuration files. The central component of this integration is the UserDBContext, which acts as the bridge between the application's domain models and the underlying SQL Server database.
This integration is responsible for defining the database structure, handling data persistence, managing relationships between entities, and seeding initial data. Configuration is modularized using the IEntityTypeConfiguration<T> interface, promoting a clean and maintainable data layer architecture.
Core Components
DbContext Registration and Configuration
The UserDBContext is registered with the application's dependency injection (DI) container at startup. This allows it to be injected into services that require database access.
The registration process in Program.cs configures the context to use SQL Server and retrieves the connection string from the application's configuration.
// File: Program.cs
builder.Services.AddDbContext<UserDBContext>(option =>
{
option.UseSqlServer(builder.Configuration.GetConnectionString("UserDataBase"));
});
Sources: Program.cs:21-24
For design-time operations like creating migrations, a factory class UserDBContextFactory is implemented. This factory is responsible for creating an instance of UserDBContext by reading the connection string directly from appsettings.json, which is essential for EF Core CLI tools.
Sources: Data/UserDBContextFactory.cs
The UserDBContext Class
UserDBContext is the main database context class, inheriting from DbContext. It exposes DbSet<T> properties for each entity, which represent the tables in the database.
The OnModelCreating method is overridden to apply all entity configurations using the Fluent API. This method serves as the central point for defining the database model.
// File: Data/UserDBContext.cs
public class UserDBContext : DbContext
{
// ... constructor ...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Apply all configurations
modelBuilder.ApplyConfiguration(new UserConfiguration());
modelBuilder.ApplyConfiguration(new OrderConfiguration());
modelBuilder.ApplyConfiguration(new ProductConfiguration());
modelBuilder.ApplyConfiguration(new AdminConfiguration());
modelBuilder.ApplyConfiguration(new CategoryConfiguration());
modelBuilder.ApplyConfiguration(new OrderItemConfiguration());
// ... relationship definitions ...
// Apply any seed data if necessary
modelBuilder.Seed();
}
// DbSet for each entity
public DbSet<User> User { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<Admin> Admins { get; set; }
public DbSet<OrderItem> OrderItems { get; set; }
public DbSet<Category> Categories { get; set; }
}
Sources: Data/UserDBContext.cs:8-38
The following diagram illustrates the flow of applying configurations when the model is being created.
This diagram shows how OnModelCreating orchestrates the application of various entity configurations and data seeding to build the final data model.
Sources: Data/UserDBContext.cs:13-20, Seeders/DatabaseSeeder.cs
Entity Relationship Schema
The database schema is defined by the model classes and their configurations. The relationships between entities like User, Order, Product, and Category are established using foreign keys.
The diagram below represents the Entity-Relationship model derived from the EF Core configurations.
This ER diagram visualizes the tables and their relationships within the database, such as the one-to-many relationship between USER and ORDER, and between ORDER and ORDER_ITEM.
Sources: Migrations/UserDBContextModelSnapshot.cs, Configuration/OrderItemConfiguration.cs:22-29, Configuration/OrderConfiguration.cs:25-27
Fluent API Entity Configurations
To keep the UserDBContext clean, entity configurations are defined in separate classes that implement IEntityTypeConfiguration<T>. This approach allows for modular and focused schema definitions for each entity.
Example: CategoryConfiguration
This class configures the Category entity, mapping it to the "Categories" table and defining constraints for its properties.
// File: Configuration/CategoryConfiguration.cs
public class CategoryConfiguration : IEntityTypeConfiguration<Category>
{
public void Configure(EntityTypeBuilder<Category> builder)
{
// Đặt tên bảng
builder.ToTable("Categories");
// Định nghĩa khóa chính
builder.HasKey(c => c.Id);
// Định nghĩa các thuộc tính
builder.Property(c => c.Name)
.IsRequired()
.HasMaxLength(100);
builder.Property(c => c.Description)
.HasMaxLength(500);
}
}
Sources: Configuration/CategoryConfiguration.cs:7-24
Example: ProductConfiguration
The configuration for the Product entity demonstrates setting column types and length constraints.
| Property | Configuration | Description |
|---|---|---|
Id | builder.HasKey(p => p.Id) | Sets Id as the primary key. |
Title | .IsRequired().HasMaxLength(100) | The title is mandatory with a max length of 100. |
Name | .IsRequired().HasMaxLength(200) | The name is mandatory with a max length of 200. |
Price | .IsRequired().HasColumnType("decimal(18,2)") | The price is mandatory and stored as a decimal. |
ProductImageUrl | .HasMaxLength(500) | The image URL has a max length of 500. |
Sources: Configuration/ProductConfiguration.cs:11-34
Relationship Configuration
Relationships are also defined using the Fluent API. For example, the many-to-many relationship between Order and Product is mediated by the OrderItem entity. The configuration in OrderItemConfiguration establishes the foreign keys to both Order and Product.
// File: Configuration/OrderItemConfiguration.cs
// Liên kết với Order và Product
builder.HasOne(oi => oi.Order)
.WithMany(o => o.OrderItems)
.HasForeignKey(oi => oi.OrderID);
builder.HasOne(oi => oi.Product)
.WithMany()
.HasForeignKey(oi => oi.ProductID);
Sources: Configuration/OrderItemConfiguration.cs:23-29
Database Seeding
The application uses an extension method on ModelBuilder to seed the database with initial data. This is useful for creating default users or lookup data when the database is first created.
The DatabaseSeeder.Seed method is called from UserDBContext.OnModelCreating and is responsible for inserting a default User.
// File: Seeders/DatabaseSeeder.cs
public static class DatabaseSeeder
{
public static void Seed(this ModelBuilder modelBuilder)
{
_ = modelBuilder.Entity<User>().HasData(
new User()
{
Id = 1,
Email = "chihtt123@gmail.com",
UserName = "chi",
Password = "123",
Role = true
}
);
}
}
Sources: Seeders/DatabaseSeeder.cs:7-21, Data/UserDBContext.cs:28
Summary
The project's EF Core integration is well-structured, leveraging a code-first approach with a central UserDBContext. The use of separate configuration classes for each entity via IEntityTypeConfiguration<T> ensures a clean separation of concerns and enhances maintainability. Relationships are clearly defined using the Fluent API, and initial data is populated through a dedicated seeder class. This setup provides a robust and scalable foundation for all data persistence operations within the WEBAPI application.