Entity Framework Code First

The ADO.net team came out with its first offering for the Code-first development in the Entity Framework. This is an alternative to the existing methodologies of Database-first and the Model-first approaches. Now the suite has 3 alternatives and any approach can be chosen depending on the requirement.

Briefly explained below are the 3 approaches:-

Database-first: – Allows you to plug-in an existing database into the application. Any change to the database also changes the data access layer in the application.

Model-first: – Allows you to make a data model (domain model) in the designer surface through entities and relationships among them. A database can be generated from the model and any changes in the model can be pushed down to the database through re-creation of the database.

Code-first: -Allows you to create a set of classes to model your business domain. These classes can be configured and tables can be created using the public attributes with these classes. Changes in these classes will trigger automatic changes in the database which can be controlled by code.

Code-first borrows two important concepts from the dynamic language paradigm, Convention over Configuration and fluent API. Before we dive into the topic below are a few basic terms that will be used: –

Entity: – Any business object that needs to be mapped to a persistent storage (e.g. sales representative, account, commission).

Mapping: -It is the act of determining how entities and their relationships will be persisted in the database.

Relationship Mapping: – It is the act of determining how the relationships (association, aggregation, composition) will be mapped to the database.

Association: -An association is the definition of the relationship between two entities (e.g. a foreign key)

Navigation Property: -It is the property that allows you to traverse from one end of the association to the other end. Navigation properties are optional but are dependent on the presence of an association for their existence.

Association Set: -Association set is the logical grouping of the association instances of the same type. It is not a data modeling construct.

Association End Multiplicity: -It defines the number of entities that can be at either end of the association. It can be 1(exactly one), 0…1(zero or one) or *(zero, one or many).

The implementation is done as follows: –

· When the multiplicity is singular (1), define a navigational property.

· When the multiplicity is plural (many) then use ICollection<T> of the Target entity involved.

Directionality of relationships: – The relationships can be Uni-directional or Bi-directional. Uni-directionality indicates that only one of the entities involved is aware of the other i.e. the navigational property exists only at one end. Bi-directionality indicates that both the entities are aware of each other and navigational property exists at both the ends.

A Simple Model

First add the entity framework package to the visual studio project. The new way is to do it through

Nu-get .

Figure 1 Adding Entity Framework Through NuGet Command Line

In the package manager console (which is powershell) do the following: –

PM> Install-Package EntityFramework

The package manager will go to the official nu-get package source and look for the package and bring it down and put it in your assemblies. The end message will be something similar to this (the version numbers can differ, the last thing represents your project name).

Successfully added ‘EntityFramework 4.1.10715.0’ to EFCodeFirst

The alternative is to use the Add Library Package Reference

Figure 2 Adding Entity Framework through NuGet Web Interface

Note: – Nuget is not available for visual studio 2010 C# express edition; we will need the standalone installer for Entity Framework.

Now, create a simple POCO class


using System;
using System.ComponentModel.DataAnnotations;
namespace EFCodeFirst
{ public class UserDetail
//[Key] public int UserDetailId
{ get; set; }
[Required] [MaxLength(10, ErrorMessage = "UserName must be 10 characters or less"), MinLength(5)]
public String Name { get; set; }
[Required] [MaxLength(20, ErrorMessage = "Password must be between 6 and 20 characters"), MinLength(6)]
public String Password { get; set; }
public String UserRole { get; set; }
public DateTime DateOfCreation { get; set; }
 }
}

Firstly, the notion of convention over configuration allows us to have UserDetailId as the primary key. EF will pick the property with class name appended with Id as the default primary key. Of course, if our requirements differ we can also use the data annotations to explicitly mark a property as key. Similarly, Foreign key can also marked in the POCO class.

The annotations associated with the properties will allow us to have the concept of DRY (Do Not Repeat Your Code).These validation will also be pushed down to the tables in the database.

Next, we will create a context for managing the entities.

using System.Data.Entity;
namespace EFCodeFirst
{
   public class MyDatabaseContext : DbContext 
   {
   public MyDatabaseContext() 
   {
   Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MyDatabaseContext>());
   }
   public DbSet<UserDetail> UserDetails { get; set; }
   protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
       modelBuilder.Entity<UserDetail>().ToTable("Users"); 
    } 
}
}

The DropCreateDatabaseIfModelChanges is a really handy because in development there will often be rapid changes and this method allows you to do that. To customize the database that the code creates we can also specify the Connection Parameters for the database using the DefaultConnectionFactory property.

How does the EF Framework know that the model has changed?

· When we first make use of the entities the framework goes ahead and creates the database (default provider is SQLExpress, we can change it to SQLCE or Oracle etc..).

· When it creates the database (if it is successful) it will generate MetaData for the model and store it in the database.

· Next time if we change something in the model (e.g. adds a new entity, modify properties or relationships) it will check the hash of the new model against the hash of the existing model.

· If the hash does not match it will realize that the model has changed and it will drop it and re-create with the new model.

· If the creation of the database fails (e.g. foreign key is not specified properly etc…), there will be no hash generated for the model. We will have manually drop the database and then re-run the code after fixing the errors.

Figure 3 EDM Meta Data Table

DbSet represents the collection of the entities in the context. The overridden method is where the real control resides for the mapping. This is where we will create your mappings specify the foreign keys and map the POCO classes to tables etc.

In the above snippet the entity UserDetail has been mapped to a table “Users”. The parameter for the ToTable(“TableName”) ,method is the name of the table in the database. This line of code borrows the concept of fluent api (basically the code flows like method1().method2().method3()……) from the dynamic languages. Fluent Api is much more than method chaining and requires more thought in the api construction.

The final thing would be to use this context and create an instance of the entity and save it to the database.


using System; using System.Linq;
using System.Data.Entity.Validation;
namespace EFCodeFirst
{
   class Program { static void Main(string[] args) {
   using (var context = new MyDatabaseContext()) {
   try
   {
       context.UserDetails.Add(new UserDetail{
                                      Name = "Ashutosh",
                                      Password = "Shyamu",
                                      UserRole = "Administrator",
                                      DateOfCreation = DateTime.Now });
       context.SaveChanges();
       var result = from u in context.UserDetails select u;
       foreach (var temp in result) 
       {
       Console.WriteLine(temp.UserDetailId + “\n” + temp.Name);
       }
    }
 
    catch (DbEntityValidationException dbe)
    {
      foreach(var error in dbe.EntityValidationErrors)
      {
          Console.WriteLine("An error has occured");
          Console.WriteLine("Property :- " + error.ValidationErrors.First().PropertyName + "\nMessage :-" +          error.ValidationErrors.First().ErrorMessage); 
      }
   }
}
 Console.ReadKey(); 
  }
 }
} 

We create an instance of the context and use that to add a new UserDetail to the context. It is imperative to call the SaveChanges() method, since it is only then that the validations kick in and the entity is pushed down to the database. If there are any errors while validating the entities the context will throw an exception and we will see our error messages that were defined as annotations for the properties of the entity.

When we run the code a new database will be created with the “Users” table.

image

Figure 4 Users Table

If we run a simple sql select query for the users table we will see the following.
image

Figure 5 an instance of UserDetail Entity in the Users Table

We did not specify the primary key when we initialized the object, yet the key was assigned. This is because the default behavior of EF is to mark primary key as auto increment. We can turn this on or off as per our requirements.

Now, assume we had initialized the object as follows: –

new UserDetail
{
Name = "Ashu",
Password = "Shyamu",
UserRole = "Administrator",
DateOfCreation = DateTime.Now
};

image

Figure 6 Exception caught when validation rules were violated

· The validation errors would be caught and we will see the error message we specified as annotation for the property.

· These validation errors can also be thrown to a view we might have in a web application or a windows application.

· These validation messages can also be globalized providing us with the capability to have messages in different languages as well.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s