Configuring Property Mapping Conventions in Entity Framework Code First

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());
}

Tags: Entity Framework Code First Data Annotations Fluent API ORM

Posted on Tue, 30 Jun 2026 16:48:53 +0000 by masalastican