Entity Framework Code First provides two primary methods for configuring the mapping between entity classes and database tables: Data Annotations and the Fluent API. The following sections demonstrate these approaches using a Product class example.
Table Name and Schema
By default, Code First creates a table name by pluralizing the clas name (e.g., Products) and uses the dbo schema. This convention can be overridden.
Using Data Annotations
First, include the necessary namespace.
using System.ComponentModel.DataAnnotations.Schema;
Specify the table name.
[Table("Product")]
public class Product
{
}
Specify both the table name and schema.
[Table("Product", Schema = "dbo")]
public class Product
{
}
Using Fluent API
Create a context class that inherits from DbContext and override the OnModelCreating method.
using System.Data.Entity;
public class PortalContext : DbContext
{
public DbSet<Product> Products { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Map to a specific table
modelBuilder.Entity<Product>().ToTable("Product");
// Map to a table with a specific schema
modelBuilder.Entity<Product>().ToTable("Product", "dbo");
}
}
Column Name, Length, Data Type, and Nullability
By default, column names match property names. These mappings can be customized.
Using Data Annotations
using System.ComponentModel.DataAnnotations;
public class Product
{
[Column("ProductID")]
public int Id { get; set; }
[Required]
[MaxLength(100)]
[Column("ProductName")]
public string Name { get; set; }
}
To specify a SQL Server data type, use the TypeName parameter.
[Column("UnitPrice", TypeName = "MONEY")]
public decimal Price { get; set; }
Using Fluent API
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>()
.Property(p => p.Id)
.HasColumnName("ProductID");
modelBuilder.Entity<Product>()
.Property(p => p.Name)
.IsRequired()
.HasMaxLength(100)
.HasColumnName("ProductName");
modelBuilder.Entity<Product>()
.Property(p => p.Price)
.HasColumnName("UnitPrice")
.HasColumnType("MONEY");
}
String properties without a MaxLength constraint map to NVARCHAR(MAX).
Primary Key Configuration
The default convention identifies a property named Id or ClassNameId as the primary key.
Using Data Annotations
using System.ComponentModel.DataAnnotations;
public class Product
{
[Key]
[Column("ProductID")]
public int Id { get; set; }
}
Using Fluent API
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Single-column key
modelBuilder.Entity<Product>().HasKey(p => p.Id);
// Composite key
modelBuilder.Entity<Product>().HasKey(p => new { p.KeyPart1, p.KeyPart2 });
}
Controlling Database-Generated Values
Integer primary keys are configured as identity columns by default. This can be changed.
Using Data Annotations
using System.ComponentModel.DataAnnotations.Schema;
public class Product
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)] // Not generated
public int Id { get; set; }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] // Identity column
public int AnotherId { get; set; }
}
Using Fluent API
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>()
.HasKey(p => p.Id)
.Property(p => p.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
}
Numeric Precision and Scale
Use the Fluent API to define precision for decimal columns, as Data Annotations do not support this.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>()
.Property(p => p.Price)
.HasPrecision(18, 2); // 18 total digits, 2 decimal places
}
Excluding Properties from the Database
To prevent a property from being mapped to a database column.
Using Data Annotations
using System.ComponentModel.DataAnnotations.Schema;
public class Product
{
[NotMapped]
public string TemporaryNote { get; set; }
}
Using Fluent API
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>().Ignore(p => p.TemporaryNote);
}
Organizing Fluent API Configurations
For better organization, create separate configuration classes that inherit from EntityTypeConfiguration<T>.
using System.Data.Entity.ModelConfiguration;
public class ProductConfiguration : EntityTypeConfiguration<Product>
{
public ProductConfiguration()
{
// Primary Key
HasKey(p => p.Id);
// Properties
Property(p => p.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
Property(p => p.Name)
.IsRequired()
.HasMaxLength(100);
// Table & Column Mappings
ToTable("Product");
Property(p => p.Id).HasColumnName("ProductID");
Property(p => p.Name).HasColumnName("ProductName");
Property(p => p.Price)
.HasColumnName("UnitPrice")
.HasPrecision(18, 2);
}
}
Register this configuraton in the OnModelCreating method.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ProductConfiguration());
}