Entity Framework Core: Modeling Data
Tip: Understanding data modeling is fundamental to effectively using Entity Framework Core (EF Core).
Introduction to Data Modeling in EF Core
Entity Framework Core provides a powerful object-relational mapper (ORM) that allows you to work with your database as if you were using regular .NET objects. Data modeling is the process of defining the structure of your data, including entities, their properties, and the relationships between them.
EF Core can infer your data model by inspecting your application's domain classes. This is known as the Code First approach. Alternatively, you can define your model explicitly using the EF Core API, or generate a model from an existing database (Database First).
Entities and Properties
Entities are the .NET classes that represent tables in your database. Each property of an entity class typically maps to a column in that table.
For example, consider a simple `Product` entity:
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
In this example, `ProductId`, `Name`, and `Price` will be mapped to columns in a `Products` table.
Convention-Based Mapping
EF Core uses conventions to automatically map your classes and properties to your database schema. Some common conventions include:
- Public classes are treated as entities.
- Properties with a public getter and setter are mapped as columns.
- A property named `Id` or `ClassNameId` is recognized as the primary key.
Relationships Between Entities
Real-world applications often involve relationships between different data entities. EF Core supports common relationship types:
- One-to-Many: One `Category` can have many `Products`.
- Many-to-One: Many `Products` can belong to one `Category`.
- One-to-One: One `User` might have one `UserProfile`.
- Many-to-Many: Many `Students` can enroll in many `Courses`.
Defining Relationships with Navigation Properties
Navigation properties are used to represent relationships. They allow you to traverse from one entity to another.
Example of a one-to-many relationship between `Category` and `Product`:
public class Category
{
public int CategoryId { get; set; }
public string Name { get; set; }
public ICollection<Product> Products { get; set; } = new List<Product>();
}
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public int CategoryId { get; set; } // Foreign key
public Category Category { get; set; }
}
In this scenario, `Category.Products` is the navigation property from `Category` to `Product`, and `Product.Category` is the navigation property from `Product` to `Category`. The `CategoryId` property in `Product` acts as the foreign key.
Configuring Your Model
While conventions are powerful, you can explicitly configure your model to override conventions or define complex mappings. This is typically done in the `OnModelCreating` method of your `DbContext` class.
Fluent API
The Fluent API allows you to configure your model using a chainable method syntax.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>()
.HasKey(p => p.ProductId); // Explicitly define primary key
modelBuilder.Entity<Product>()
.Property(p => p.Name)
.IsRequired()
.HasMaxLength(100); // Configure property constraints
modelBuilder.Entity<Product>()
.HasOne(p => p.Category) // Configure one-to-many relationship
.WithMany(c => c.Products)
.HasForeignKey(p => p.CategoryId);
}
Data Annotations
You can also use data annotations as attributes directly on your entity classes.
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
public class Product
{
[Key] // Data annotation for primary key
public int ProductId { get; set; }
[Required] // Data annotation for not null
[StringLength(100)] // Data annotation for max length
public string Name { get; set; }
[Column(TypeName = "decimal(18, 2)")] // Specify database type
public decimal Price { get; set; }
[ForeignKey("Category")] // Data annotation for foreign key
public int CategoryId { get; set; }
public Category Category { get; set; }
}
Key Concepts Recap
- Entities: Classes representing database tables.
- Properties: Map to database columns.
- Primary Keys: Uniquely identify entities. EF Core conventions often auto-detect them.
- Foreign Keys: Establish relationships between tables.
- Navigation Properties: Allow traversal between related entities.
- Fluent API: Powerful configuration via code.
- Data Annotations: Attribute-based configuration.
Next Steps
Continue exploring how to leverage EF Core for efficient data access and management in your .NET applications. Consider learning about:
- EF Core Migrations for managing database schema changes.
- Querying Data with LINQ.
- Saving Data and managing transactions.