Looking into Code First Data Annotations in Entity Framework
In this post I would like to talk about Data Annotations and how to use them in our Code First Entity framework applications.Developers use extensively EF to build their data access layer. We have 3 development paradigms in EF. We have Database First,Model First and Code First. The last one (Code First) gains increasing popularity amongst developers.
I will use another post also found in this blog to demonstrate Data Annotations.In order to fully understand what I am talking about, you need to read this post titled Using the Code First approach when building ASP.Net applications with Entity Framework . It will take some time to create this application but it is necessary in order to follow along.
With Data Annotations we can configure our domain-entity classes so that they can take best advantage of the EF.We can decorate our entity classes with declarative attributes.Let me give you an insight on how EF Code First works.EF Code First at run time, looks at the entity-domain classes and infers from them the in-memory data that it needs to interpret the queries and interact with the database.For example it assumes that any property named ID represents the key property of the class.Data Annotations "live" inside the System.ComponentModel.DataAnnotations. We do add Data Annotations to our domain classes declaratively using attributes. You can also do that imperatively using the Fluent API but this is beyond the scope of this post.
I will use these two entity classes
public class Footballer { public int FootballerID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public double Weight { get; set; } public double Height { get; set; } public List<Training> Trainings { get; set; } }
public class Training { public int TrainingID { get; set; } public int TrainingDuration { get; set; } public string TrainingLocation { get; set; } }
1) Make sure you run the application I mentioned earlier. I have already installed SQL Server 2012 Express edition in my laptop. A database is created and populated when the application runs.This happens through the magic of EF and Data Annotations.I launch SSMS connect to the instance of SQL Server 2012 Express and I browse to the database EfCodeFirstASPnet.CodeFirst.FootballerDBContext
Make sure you have a look at the tables and tables columns.
Have a look at the picture below
You can see this information through the VS 2012 IDE.Make sure you have opened the Server Object Explorer. I connect to the SQL Server Express Edition through that window.
Have a look at the picture below
2) Now let me explain how EF knows how to build the tables, the columns, the data types and the various attributes (null , not null e.t.c).You have to understand that the EF Code First Model works with conventions.
- The table names are derived from the entity class names
- I have a primary key in Footballers (FootballerID) table and a primary key in Trainings (TrainingID) table.How does EF do that?By default Code First will look either for a property with the name id to create the primary key or the class name (Footballer) + Id.This is the default behaviour.
- All the string properties in my EF classes became nvarchar(max,null) .This is default behaviour.
- A foreign key - Footballer_FootballerID is added.This is created by Code First using the default convention.In this case the name of the Primary entity class (Footballer) and its key field (FootballerID)
So far everything works fine and EF Code First follows all the conventions to create the tables.
Let me break some of the conventions.I go back to the Footballer Entity class and change FootballerID property to AFootballPlayer
public class Footballer { public int AFootballPlayer { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public double Weight { get; set; } public double Height { get; set; } public List<Training> Trainings { get; set; } }
When I run the application again I get an error.
Please have a look at the picture below
3) The way to correct it is to add the Key attribute to the property.
The new class definition follows
public class Footballer
{
[Key]
public int AFootballPlayer { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public double Weight { get; set; }
public double Height { get; set; }
public DateTime JoinedTheClub { get; set; }
public int Age { get; set; }
public List<Training> Trainings { get; set; }
}
Then I build and run my application.Everything works fine.Have a look at the picture below
Make sure you add a reference to the System.ComponentModel.DataAnnotations namespace in the class file
using System.ComponentModel.DataAnnotations;
Now let's see the effect the change has on the database. All the changes are propagated to the database through EF Code First.
Have a look at the picture below.Please note the changes in the primary key and foreign key.
4) Now l will demonstrate the Required attribute.
I want the FirstName property to be "Required".
The way to do it is to add the Required attribute to the desired property.
The new class definition follows
public class Footballer{
[Key]
public int AFootballPlayer { get; set; }
[Required]
public string FirstName { get; set; }
public string LastName { get; set; }
public double Weight { get; set; }
public double Height { get; set; }
public DateTime JoinedTheClub { get; set; }
public int Age { get; set; }
public List<Training> Trainings { get; set; }
}
I want the FirstName property to be "Required".
Have a look at the picture below to see the effect the new annotation has on the database schema.The column FirstName is not nullable.
5) Now l will demonstrate the ΜaxLength attribute.
The way to correct it is to add the ΜaxLength attribute to the property LastName.
The new class definition follows
public class Footballer{
[Key]
public int AFootballPlayer { get; set; }
[Required]
public string FirstName { get; set; }
[Required,MaxLegth(40)]
public string LastName { get; set; }
public double Weight { get; set; }
public double Height { get; set; }
public DateTime JoinedTheClub { get; set; }
public int Age { get; set; }
public List<Training> Trainings { get; set; }
}
Then I run the application again and the database is re-initialised. Have a look at the picture below. The LastName column is not nullable and nvarchar(40).
6) Let me show you some more attributes that are relevant to the table and columns.
I will change the name and the schema of the Footballers table.I also change the column name, the order and the data type of the JoinedTheClub property.
The new class definition follows.
[Table("FootballPlayers",Schema="guest")]
public class Footballer
{
[Key,Column(Order=0)]
public int AFootballPlayer { get; set; }
[Required]
public string FirstName { get; set; }
[Required,MaxLength(40)]
public string LastName { get; set; }
public double Weight { get; set; }
public double Height { get; set; }
[Column("ContractSigned",Order=1,TypeName="date")]
public DateTime JoinedTheClub { get; set; }
public int Age { get; set; }
public List<Training> Trainings { get; set; }
}
I build and run the application.My application compiles.
Have a look at the picture below. The database is re-initialised to reflect the changes the EF Code First propagates to the database.
There are more attributes one can use. One of them is ConcurrencyCheck.I can annotate the LastName property with this attribute. Have a look at the picture below. EF now knows that this field will be marked for concurrency cheks when we have update and delete operations.
[ConcurrencyCheck]
public string LastName { get; set; }
There are more attributes one can use to decorate with data annotations the properties of the entity classes. I hope I demonstrated the concept extensively.
In a future post I will demonstrate how to achieve all the above using the EF Code Fluent API.
Hope it helps!!!