Back to: Entity Framework Tutorials For Begineers and Professionals
Property Configuration using Entity Framework Fluent API
In this article, I am going to discuss Property Configuration using Entity Framework Fluent API with Examples. Please read our previous article where we discussed Entity Configurations using Entity Framework Fluent API with Examples.
Property Configurations using Entity Framework Fluent API
The Entity Framework Fluent API can also be used to configure the properties of an entity to map it with the database column in the database. Using Entity Framework Fluent API, we can change the corresponding column name, data type, and size. We can also configure whether the column is going to be Null or NotNull. It is also possible to configure the PrimaryKey, ForeignKey, concurrency column, etc in the database using Entity Framework Fluent API Property Configurations. The point that you need to remember is that modelBuilder.Entity<TEntity>() returns the EntityTypeConfiguration object using which we can configure the properties of an entity.
Examples to Understand Property Mappings using Entity Framework Fluent API
To understand Property Configurations in Entity Framework Code First Approach using Fluent API, we are going to use the following Student and Standard Entities.
Student.cs
using System; namespace EFCodeFirstDemo { public class Student { public int StudentRegdNumber { get; set; } public int StudentRollNumber { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Branch { get; set; } public byte[] Photo { get; set; } public decimal Height { get; set; } public float Weight { get; set; } public Standard Standard { get; set; } } }
Standard.cs
using System.Collections.Generic; namespace EFCodeFirstDemo { public class Standard { public int StandardKey { get; set; } public string StandardName { get; set; } public string Description { get; set; } public ICollection<Student> Students { get; set; } } }
Please make sure to have the connection string with the name MyConnectionString within the app.config file or web.config file as shown in the below image.
Configuring Primary Key and Composite Primary Key using Fluent API
Let us understand how to Configure Primary Key and Composite Primary Key using Entity Framework Fluent API with an example. If you see both domain classes, they do not have either Id or <Entity Name>+ “Id” properties, and hence entity framework will not follow the default code-first conventions while generating the database tables. So, in situations like this, we can go with Entity Framework Fluent API and configure the key property using the HasKey() method.
For a better understanding, please modify the context class as follows. Here, we have marked the StudentRegdNumber property of the Student Entity and StandardKey property of the Standard Entity as the Primary key using the HasKey Fluent API method. When the Primary key (Not Composite Primary Key) is created on integer data type, then it will be created as an Identity column in the database.
using System.Data.Entity; namespace EFCodeFirstDemo { public class EFCodeFirstContext : DbContext { public EFCodeFirstContext() : base("name=MyConnectionString") { //Setting the Database Initializer as DropCreateDatabaseAlways Database.SetInitializer(new DropCreateDatabaseAlways<EFCodeFirstContext>()); } protected override void OnModelCreating(DbModelBuilder modelBuilder) { //Configure Primary Key using HasKey method modelBuilder.Entity<Student>().HasKey(s => s.StudentRegdNumber); modelBuilder.Entity<Standard>().HasKey(s => s.StandardKey); } public DbSet<Student> Students { get; set; } public DbSet<Standard> Standards { get; set; } } }
Next, modify the Main method of the Program class as follows. Here, we are simply adding one student entity to the database.
using System; namespace EFCodeFirstDemo { class Program { static void Main(string[] args) { using (EFCodeFirstContext context = new EFCodeFirstContext()) { var student = new Student() { FirstName = "Pranaya", LastName = "Rout" }; context.Students.Add(student); context.SaveChanges(); Console.WriteLine("Student Added"); } Console.ReadKey(); } } }
With the above changes in place, run the application and verify the database table and check the primary key columns. Here, you can see, StudentRegdNumber and StandardKey will be created as Primary keys as shown in the below image.
Switching off Identity for Numeric Primary Key using Fluent API:
The Identity column will be generated for the Numeric key only. If you want to provide the values explicitly for the primary key column, then you need to switch off the identity. To do so, you need to use the following HasDatabaseGeneratedOption method and you need to set the value as DatabaseGeneratedOption.None
- HasDatabaseGeneratedOption(DatabaseGeneratedOption? databaseGeneratedOpti): It configures how values for the property are generated by the database.
For a better understanding, please modify the context class as follows. Here, we set the StudentRegdNumber property to DatabaseGeneratedOption.None to indicate that the value will not be generated by the database.
using System.ComponentModel.DataAnnotations.Schema; using System.Data.Entity; namespace EFCodeFirstDemo { public class EFCodeFirstContext : DbContext { public EFCodeFirstContext() : base("name=MyConnectionString") { //Setting the Database Initializer as DropCreateDatabaseAlways Database.SetInitializer(new DropCreateDatabaseAlways<EFCodeFirstContext>()); } protected override void OnModelCreating(DbModelBuilder modelBuilder) { //Configure Primary Key using HasKey method modelBuilder.Entity<Student>().HasKey(s => s.StudentRegdNumber); //Switching off Identity for StudentRegdNumber Column modelBuilder.Entity<Student>().Property(t => t.StudentRegdNumber).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); //Configure Primary Key using HasKey method modelBuilder.Entity<Standard>().HasKey(s => s.StandardKey); } public DbSet<Student> Students { get; set; } public DbSet<Standard> Standards { get; set; } } }
Can we create a primary key on string property using Fluent API?
The point that you need to remember is unlike the Data Annotation Attribute, here we can make any data type property a key property. With Data Annotation Attribute, we can only make the integral data type a key property. Now, modify the context class as follows. Here, we are making the FirstName of the Student Entity the Primary Key column in the database. In this case, it will create the column as the primary key column in the database but without identity.
using System.Data.Entity; namespace EFCodeFirstDemo { public class EFCodeFirstContext : DbContext { public EFCodeFirstContext() : base("name=MyConnectionString") { //Setting the Database Initializer as DropCreateDatabaseAlways Database.SetInitializer(new DropCreateDatabaseAlways<EFCodeFirstContext>()); } protected override void OnModelCreating(DbModelBuilder modelBuilder) { //Configure Primary Key using HasKey method modelBuilder.Entity<Student>().HasKey(s => s.FirstName); modelBuilder.Entity<Standard>().HasKey(s => s.StandardKey); } public DbSet<Student> Students { get; set; } public DbSet<Standard> Standards { get; set; } } }
With the above changes in place, run the application and you will see that the FirstName column will be created as the Primary Key column in the Students table as shown in the below image. In this case, the column will not be created as an Identity column in the database.
Configure Composite Primary Key using Entity Framework Fluent API:
It is also possible to configure composite primary key using the Entity Framework Fluent API HasKey method. In this case, we need to create an anonymous object, and using lambda expression we need to specify multiple properties. For a better understanding, please modify the context class as follows. Here, we are making the Primary key with the combination of the StudentRegdNumber and StudentRollNumber properties of the Student Entity. In the case of composite primary, it will not create an identity column.
using System.Data.Entity; namespace EFCodeFirstDemo { public class EFCodeFirstContext : DbContext { public EFCodeFirstContext() : base("name=MyConnectionString") { //Setting the Database Initializer as DropCreateDatabaseAlways Database.SetInitializer(new DropCreateDatabaseAlways<EFCodeFirstContext>()); } protected override void OnModelCreating(DbModelBuilder modelBuilder) { //Configure composite primary key using HasKey method modelBuilder.Entity<Student>().HasKey(s => new { s.StudentRegdNumber, s.StudentRollNumber }); //Configure Primary Key using HasKey method modelBuilder.Entity<Standard>().HasKey(s => s.StandardKey); } public DbSet<Student> Students { get; set; } public DbSet<Standard> Standards { get; set; } } }
With the above changes in place, now run the application and verify the database. You should see the Primary key created on both the StudentRegdNumber and StudentRollNumber columns of the Students table in the database as shown in the below image.
Configure Column Name, Type, and Order using Entity Framework Fluent API
As we already discussed, the Entity Framework default Code-First convention will create a column in the database for a property with the same name, same order, and same datatype of the Property of an Entity. We have already discussed, how to override this default configuration using Entity Framework Data Annotation Attribute. Now, we will see how we can override the default Code-First convention using Entity Framework Fluent API to configure Column Name, Type, and Order. To configure the column name, we need to use the HasColumnName method, to configure the column order we need to use the HasColumnOrder method and to configure the column data type, we need to use the HasColumnType method.
- HasColumnOrder(): It configures the order of the database column used to store the property. This method is also used to specify key ordering when an entity type has a composite key.
- HasColumnType(): It configures the data type of the database column used to store the property.
- HasColumnName(): It configures the name of the database column used to store the property.
Let us understand this with an example. First, modify the Student Entity as follows.
using System; namespace EFCodeFirstDemo { public class Student { public int StudentId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public DateTime DateOfBirth { get; set; } } }
For a better understanding, please modify the context class as follows. Here, we are configuring the DateOfBirth Property of the Student Entity to set the database column name for this property as DOB, Column Order as 2, and column data type as datetime2.
using System.Data.Entity; namespace EFCodeFirstDemo { public class EFCodeFirstContext : DbContext { public EFCodeFirstContext() : base("name=MyConnectionString") { //Setting the Database Initializer as DropCreateDatabaseAlways Database.SetInitializer(new DropCreateDatabaseAlways<EFCodeFirstContext>()); } protected override void OnModelCreating(DbModelBuilder modelBuilder) { //Configure Column Name, Order, and Type modelBuilder.Entity<Student>() .Property(p => p.DateOfBirth) .HasColumnName("DOB") .HasColumnOrder(2) .HasColumnType("datetime2"); } public DbSet<Student> Students { get; set; } } }
Now, run the above code and verify the database. You should see the column will be created as expected as shown in the below image.
As you can see everything is fine except the column order. This is because we have not specified the Column Order of all the properties. To work this correctly we need to specify the column order of all properties as follows.
using System.Data.Entity; namespace EFCodeFirstDemo { public class EFCodeFirstContext : DbContext { public EFCodeFirstContext() : base("name=MyConnectionString") { //Setting the Database Initializer as DropCreateDatabaseAlways Database.SetInitializer(new DropCreateDatabaseAlways<EFCodeFirstContext>()); } protected override void OnModelCreating(DbModelBuilder modelBuilder) { //Configure Column Name, Order, and Type modelBuilder.Entity<Student>() .Property(p => p.DateOfBirth) .HasColumnName("DOB") .HasColumnOrder(2) .HasColumnType("datetime2"); modelBuilder.Entity<Student>() .Property(p => p.StudentId) .HasColumnOrder(0); modelBuilder.Entity<Student>() .Property(p => p.FirstName) .HasColumnOrder(1); modelBuilder.Entity<Student>() .Property(p => p.LastName) .HasColumnOrder(3); } public DbSet<Student> Students { get; set; } } }
Now, run the above code and verify the database. You should see the column order will be created as expected as shown in the below image.
Configure Null or NotNull Columns using Entity Framework Fluent API
As we already discussed, the Entity Framework API by default will create a NotNull column for all the primitive data type properties. This is because by default the primitive data types in C# cannot hold null values. If you want to store null, then you need to make the property nullable using ? sign or Nullable<T> data type.
Suppose you have a string property in your Entity that can hold a null value and for the string property the Entity Framework API will create a column as NULL type in the database. Now, if you want to create the string property as a NOT NULL type in the database, then you need to the IsRequired() Fluent API method. Similarly, if you have a primitive property and you want to make the corresponding column a Nullable in the database, then you need to use the IsOptional() Fluent API method.
- IsRequired(): It configures the property to be required. The database column used to store this property will be non-nullable.
- IsOptional(): It configures the property to be optional. The database column used to store this property will be nullable. String properties are optional by default.
For a better understanding, first, let us modify the Student Entity as follows. By default, the Entity Framework will create NULL for string Properties and NOT NULL for int types in our example.
namespace EFCodeFirstDemo { public class Student { public int StudentId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public int StudentRegdNumber { get; set; } } }
Now, what is our requirement, we need to create the First Name column as NOT NULL in the database and the StudentRegdNumber column as NULL in the database. To do so, modify the context class as follows. Here, you can see we are using the IsRequired method with the FirstName property and IsOptional method with the StudentRegdNumber property.
using System.Data.Entity; namespace EFCodeFirstDemo { public class EFCodeFirstContext : DbContext { public EFCodeFirstContext() : base("name=MyConnectionString") { //Setting the Database Initializer as DropCreateDatabaseAlways Database.SetInitializer(new DropCreateDatabaseAlways<EFCodeFirstContext>()); } protected override void OnModelCreating(DbModelBuilder modelBuilder) { //Configure NOT NULL for FirstName column which is by default NULL modelBuilder.Entity<Student>() .Property(p => p.FirstName) .IsRequired(); //Configure NULL for StudentRegdNumber column which is by default NOT NULL modelBuilder.Entity<Student>() .Property(p => p.StudentRegdNumber) .IsOptional(); } public DbSet<Student> Students { get; set; } } }
With the above changes in place, run the above code and verify the database. You should see the columns with NULL and NOT NULL constraints as expected as shown in the below image.
Configure Column Size using Entity Framework Fluent API
It is also possible to set the column size using Entity Framework Fluent API. By default, for string or byte[] properties of an entity, Entity Framework will set the size of the database column as max. For string properties, it will create the column as nvarchar(max) and for byte[] properties, it will create the column as varbinary(max). And for the decimal property, it will create the database column as decimal(18, 2).
To override the default size, we need to use the following HasMaxLength and HasPrecision Fluent API Methods in Entity Framework.
- HasMaxLength(int? value): It configures the property to have the specified maximum length. Here, the value parameter specifies the maximum length for the property. Setting ‘null’ will remove any maximum length restriction from the property and a default length will be used for the database column.
- HasPrecision(byte precision, byte scale): It configures the precision and scale of the property. Here, the precision parameter specifies the precision of the property and the scale parameter specifies the scale of the property.
- IsFixedLength(): It configures the property to be fixed length. Use HasMaxLength to set the length that the property is fixed to.
- IsVariableLength(): It configures the property to be variable length. String properties are variable length by default.
First, modify the Student entity class as follows.
namespace EFCodeFirstDemo { public class Student { public int StudentId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public decimal Height { get; set; } public float Weight { get; set; } public byte[] Photo { get; set; } } }
Let us first check the default data type and size of the column and then we will see how we can change the size of the column using Fluent API. So, modify the context class as follows.
Now, run the application and verify the database and you should see the database column with the default size and data type as shown in the below image.
Next, modify the context class as follows. Here, you can see, we have applied the HasMaxLength method on the FirstName and LastName properties and the IsFixedLength method on the LastName property. We have also applied the HasPrecision method on the Height Property.
using System.Data.Entity; namespace EFCodeFirstDemo { public class EFCodeFirstContext : DbContext { public EFCodeFirstContext() : base("name=MyConnectionString") { //Setting the Database Initializer as DropCreateDatabaseAlways Database.SetInitializer(new DropCreateDatabaseAlways<EFCodeFirstContext>()); } protected override void OnModelCreating(DbModelBuilder modelBuilder) { //Set FirstName column size to 50, by default data type as nvarchar i.e. variable length modelBuilder.Entity<Student>() .Property(p => p.FirstName) .HasMaxLength(50); //Optionally, you can also call IsVariableLength length method to make the data type as nvarchar //modelBuilder.Entity<Student>() // .Property(p => p.FirstName) // .HasMaxLength(50) // .IsVariableLength(); //Set LastName column size to 50 and change datatype to nchar //IsFixedLength() change datatype from nvarchar to nchar modelBuilder.Entity<Student>() .Property(p => p.LastName) .HasMaxLength(50) .IsFixedLength(); //Set Height column size to decimal(2,2) modelBuilder.Entity<Student>() .Property(p => p.Height) .HasPrecision(2, 2); } public DbSet<Student> Students { get; set; } } }
With the above changes in place, run the application and verify the database and you should see the database column with the appropriate size and data type as expected as shown in the below image.
Configure Concurrency Column using Entity Framework Fluent API
We can configure a property of an entity as a concurrency column using the following Entity Framework Fluent API ConcurrencyToken() and IsRowVersion() methods.
- IsConcurrencyToken(): It configures the property to be used as an optimistic concurrency token. So, using the concurrency column we can handle the Concurrency Issues. The Concurrency issue arises when multiple users or multiple transactions attempt to update/delete the same row at the same time. This method is used with string-type properties.
- IsRowVersion(): Configures the property to be a row version in the database. The actual data type will vary depending on the database provider being used. Setting the property to be a row version will automatically configure it to be an optimistic concurrency token. using the concurrency column, we can handle the Concurrency Issues. The Concurrency issue arises when multiple users or multiple transactions attempt to update/delete the same row at the same time.
Let us understand this with an example. First, modify the Student entity class as follows:
namespace EFCodeFirstDemo { public class Student { public int StudentId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public byte[] RowVersion { get; set; } } }
Next, modify the context class as follows. Here, you can see, we have applied the IsConcurrencyToken method on the FirstName property and the IsRowVersion method on the RowVersion property.
using System.Data.Entity; namespace EFCodeFirstDemo { public class EFCodeFirstContext : DbContext { public EFCodeFirstContext() : base("name=MyConnectionString") { //Setting the Database Initializer as DropCreateDatabaseAlways Database.SetInitializer(new DropCreateDatabaseAlways<EFCodeFirstContext>()); } protected override void OnModelCreating(DbModelBuilder modelBuilder) { //Set StudentName as concurrency column modelBuilder.Entity<Student>() .Property(p => p.FirstName) .IsConcurrencyToken(); //Set RowVersion as timestamp column modelBuilder.Entity<Student>() .Property(p => p.RowVersion) .IsRowVersion(); } public DbSet<Student> Students { get; set; } } }
With the above changes in place, run the application code and verify the database and you should see the following.
Note: For more details and to understand how concurrency issues can be handled using the concurrency column, please click here.
How to Ignore Table and Column Mapping using Fluent API?
To Ignore Table and Column Mapping using Entity Framework Fluent API, we can use the Ignore Method.
Ignore Property Mapping using Fluent API:
The Fluent API Ignore method is used to disable the mapping of property to a column in the database. Let us understand this with an example. First, modify the Student Entity class as follows.
namespace EFCodeFirstDemo { public class Student { public int StudentId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Branch { get; set; } } }
Now, while generating the database for the above Student Entity, we do not want to map the Branch property in the corresponding database. To Ignore the Branch property, we need to modify the Student class as follows. Here, you can see, on the Student entity, we are calling the Ignore method and specifying the Branch property.
using System.Data.Entity; namespace EFCodeFirstDemo { public class EFCodeFirstContext : DbContext { public EFCodeFirstContext() : base("name=MyConnectionString") { //Setting the Database Initializer as DropCreateDatabaseAlways Database.SetInitializer(new DropCreateDatabaseAlways<EFCodeFirstContext>()); } protected override void OnModelCreating(DbModelBuilder modelBuilder) { //Ignore the Branch Property while generating the database modelBuilder.Entity<Student>().Ignore(t => t.Branch); } public DbSet<Student> Students { get; set; } } }
With the above changes in place, now run the application and verify the database, you will see that the Branch column is not in the Students database as shown in the below image. In this case, Ignore method excludes property from the model so that it will not be mapped to the database.
Ignore Table Mapping using Fluent API
The Fluent API Ignore Method of the modelBuilder class can also be used to exclude the database mapping for the specified entity. For better understanding, please modify the context class as follows. The following example code will ensure that the Standard table is not created in the database.
using System.Data.Entity; namespace EFCodeFirstDemo { public class EFCodeFirstContext : DbContext { public EFCodeFirstContext() : base("name=MyConnectionString") { //Setting the Database Initializer as DropCreateDatabaseAlways Database.SetInitializer(new DropCreateDatabaseAlways<EFCodeFirstContext>()); } protected override void OnModelCreating(DbModelBuilder modelBuilder) { //Ignore the Branch Property while generating the database modelBuilder.Entity<Student>().Ignore(t => t.Branch); //Ignore the Standard Entity while generating the database modelBuilder.Ignore<Standard>(); } public DbSet<Student> Students { get; set; } public DbSet<Standard> Standards { get; set; } } }
As you can see in the above example code, we have created Standard Entity as a DbSet property. But then we used the Ignore method and specify the Standard Entity which will exclude the Standard entity while generating the database. With the above changes in place, run the application code and verify the database. You should see only the Students table, but not the Standard table in the database as shown in the below image.
In the next article, I am going to discuss Entity Relationships in Entity Framework Code First Approach with Examples. Here, in this article, I try to explain Entity Configurations using Fluent API in Entity Framework Code First Approach with Examples. I hope you enjoyed this Entity Configurations using Fluent API in Entity Framework Code First Approach article. Please give your valuable feedback and suggestions about this article.