Entity Framework Code First
The Code First approach in Entity Framework (EF) allows you to create a data model by writing C# or VB.NET classes. EF then generates the database schema based on your model. This is ideal for developers who prefer to work with objects and conventions over manually designing database tables.
What is Code First?
Code First flips the traditional Entity Framework workflow. Instead of generating classes from an existing database, you define your domain model using plain .NET classes. Entity Framework then infers the database structure from these classes. This approach aligns well with Domain-Driven Design (DDD) principles and test-driven development (TDD).
Key Benefits
- Productivity: Quickly define your domain model in code, letting EF handle database creation.
- Flexibility: Easily refactor your domain model without direct database manipulation.
- Testability: Develop and test your domain logic independently of the database.
- Convention over Configuration: EF uses conventions to infer mappings, reducing the need for explicit configuration.
Getting Started with Code First
To use Code First, you typically need to:
- Install Entity Framework: Use NuGet Package Manager to install the
EntityFramework
package. - Define Your Domain Models: Create your C# classes representing entities, for example,
Product
,Category
, etc. - Define Your DbContext: Create a class that derives from
System.Data.Entity.DbContext
. This class represents your database session and will containDbSet<TEntity>
properties for each of your domain models. - Configure Mappings (Optional): While EF infers mappings by convention, you can use Data Annotations or the Fluent API to customize table names, column properties, relationships, and more.
- Create the Database: When your application first runs, EF can automatically create the database or update an existing one based on your model. This is often managed using EF Migrations.
Example: Simple Domain Model
Consider the following simple domain model:
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public virtual Blog Blog { get; set; }
}
Example: DbContext
Here's a corresponding DbContext
:
using System.Data.Entity;
public class BloggingContext : DbContext
{
public BloggingContext() : base("name=BloggingDatabase") // Connection string name
{
}
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Further configurations can be added here using Fluent API
base.OnModelCreating(modelBuilder);
}
}
Data Annotations
You can use Data Annotations to configure your model directly on your classes:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Collections.Generic;
public class Product
{
[Key] // Marks ProductId as the primary key
public int ProductId { get; set; }
[Required] // Makes the Name property non-nullable in the database
[StringLength(100)] // Sets the maximum length of the Name column
public string Name { get; set; }
[Column(TypeName = "decimal(18,2)")] // Specifies the database column type
public decimal Price { get; set; }
public int CategoryId { get; set; }
[ForeignKey("CategoryId")] // Configures the relationship
public virtual Category Category { get; set; }
}
Fluent API
For more complex configurations, the Fluent API provides a powerful way to define mappings within your DbContext
:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Configure entity properties
modelBuilder.Entity<Product>()
.HasKey(p => p.ProductId); // Primary Key
modelBuilder.Entity<Product>()
.Property(p => p.Name)
.IsRequired()
.HasMaxLength(100); // String length constraint
modelBuilder.Entity<Product>()
.Property(p => p.Price)
.HasColumnType("decimal(18,2)"); // Database column type
// Configure relationships
modelBuilder.Entity<Product>()
.HasRequired(p => p.Category) // One-to-many: Product must have a Category
.WithMany(c => c.Products) // One-to-many: Category can have many Products
.HasForeignKey(p => p.CategoryId); // Foreign key property
// Rename tables
modelBuilder.Entity<Product>().ToTable("Products");
modelBuilder.Entity<Category>().ToTable("Categories");
base.OnModelCreating(modelBuilder);
}
Tip:
Entity Framework Migrations are essential for managing changes to your Code First model over time and synchronizing them with your database schema.
Note:
The connection string for your database is typically configured in your application's configuration file (e.g., App.config
or Web.config
).