Property Mappings using Fluent API:

The Fluent API can be used to configure properties of an entity to map it with a db column. Using Fluent API, you can change the corresponding column name, type, size, Null or NotNull, PrimaryKey, ForeignKey, concurrency column, etc.

We will configure the following entity classes.

public class Student
{
    public int StudentKey { get; set; }
    public string StudentName { get; set; }
    public DateTime DateOfBirth { get; set; }
    public byte[]  Photo { get; set; }
    public decimal Height { get; set; }
    public float Weight { get; set; }
        
    public Standard Standard { get; set; }
}
    
public class Standard
{
    public int StandardKey { get; set; }
    public string StandardName { get; set; }
    
    public ICollection<Student> Students { get; set; }
}

Configure Primary Key and Composite Primary Key:

Our domain classes above, do not follow the Code-First convention for primary key because they don't have Id or {Class Name} + "Id" property. So, you can configure a key property using the HasKey() method as shown below. Remember that modelBuilder.Entity<TEntity>() returns the EntityTypeConfiguration object.

public class SchoolContext: DbContext 
{
    public SchoolDBContext(): base() 
    {
    }

    public DbSet<Student> Students { get; set; }
    public DbSet<Standard> Standards { get; set; }
        
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //Configure primary key
        modelBuilder.Entity<Student>().HasKey<int>(s => s.StudentKey);
        modelBuilder.Entity<Standard>().HasKey<int>(s => s.StandardKey);

        //Configure composite primary key
        modelBuilder.Entity<Student>().HasKey<int>(s => new { s.StudentKey, s.StudentName }); 
    }
}
        

Configure Column Name, Type and Order:

The default Code-First convention creates a column for a property with the same name, order, and datatype. You can override this convention, as shown below.

public class SchoolContext: DbContext 
{
    public SchoolDBContext(): base() 
    {
    }

    public DbSet<Student> Students { get; set; }
    public DbSet<Standard> Standards { get; set; }
        
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //Configure Column
        modelBuilder.Entity<Student>()
                    .Property(p => p.DateOfBirth)
                    .HasColumnName("DoB")
                    .HasColumnOrder(3)
                    .HasColumnType("datetime2");
    }
}
        

As you can see in the above example, the Property() method is used to configure a property of an entity. The HasColumnName() method is used to change the column name of the DateOfBirth property. Also, the HasColumnOrder() and HasColumnType() methods change the order and datatype of the corresponding column.

modelBuilder.Entity<TEntity>().Property(expression) allows you to use different methods to configure a particular property, as shown below.

configure property with fluent api Entity Framework code-first

Configure Null or NotNull Column:

EF 6 API will create a NotNull column for a primitive data type property because primitive data type can not be null unless it is marked as nullable using the ? sign or Nullable<T> type.

Use IsOptional() method to create a nullable column for a property. In the same way, use IsRequired() method to create a NotNull column.

public class SchoolContext: DbContext 
{
    public SchoolDBContext(): base() 
    {
    }

    public DbSet<Student> Students { get; set; }
    public DbSet<Standard> Standards { get; set; }
        
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
            //Configure Null Column
        modelBuilder.Entity<Student>()
                .Property(p => p.Heigth)
                .IsOptional();
                        
            //Configure NotNull Column
            modelBuilder.Entity<Student>()
                .Property(p => p.Weight)
                .IsRequired();
    }
}

Configure Column Size:

Code-First will set the maximum size of a data type for a column. You can override this convention, as shown below.

public class SchoolContext: DbContext 
{
    public SchoolDBContext(): base() 
    {
    }

    public DbSet<Student> Students { get; set; }
    public DbSet<Standard> Standards { get; set; }
        
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //Set StudentName column size to 50
        modelBuilder.Entity<Student>()
                .Property(p => p.StudentName)
                .HasMaxLength(50);
                        
        //Set StudentName column size to 50 and change datatype to nchar 
        //IsFixedLength() change datatype from nvarchar to nchar
        modelBuilder.Entity<Student>()
                .Property(p => p.StudentName)
                .HasMaxLength(50).IsFixedLength();
                        
        //Set size decimal(2,2)
            modelBuilder.Entity<Student>()
                .Property(p => p.Height)
                .HasPrecision(2, 2);
    }
}

As you can see in the above example, we used the HasMaxLength() method to set the size of a column. The IsFixedLength() method converts nvarchar to nchar type. In the same way, the HasPrecision() method changed the precision of the decimal column.

Configure Concurrency Column:

You can configure a property as concurrency column using the ConcurrencyToken() method, as shown below.

public class SchoolContext: DbContext 
{
    public SchoolDBContext(): base() 
    {
    }

    public DbSet<Student> Students { get; set; }
    public DbSet<Standard> Standards { get; set; }
        
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //Set StudentName as concurrency column
        modelBuilder.Entity<Student>()
                .Property(p => p.StudentName)
                .IsConcurrencyToken();
    }
}

As you can see in the above example, we set the StudentName column as concurrency column so that it will be included in the where clause in update and delete commands.

You can also use the IsRowVersion() method for byte[] type property to make it as a concurrency column.


Test Your Entity Framework Knowledge: