Thursday 15 December 2016

EF Code First 8:Config Domain

Configure Domain Classes in Code-First

We learned default Code-First Conventions in the previous section. Code-First builds conceptual model from your domain classes using default conventions. Code-First leverages a programming pattern referred to as convention over configuration. It means you can override these conventions by configuring your domain classes to provide EF with the information it needs. There are two ways to configure your domain classes.
  1. DataAnnotations
  2. Fluent API

DataAnnotation:

DataAnnotation is a simple attribute based configuration, which you can apply to your domain classes and its properties. You can find most of the attributes in the System.ComponentModel.DataAnnotations namespace. However, DataAnnotation provides only a subset of Fluent API configurations. So, if you don't find some attributes in DataAnnotation, then you have to use Fluent API to configure it.
Following is an example of DataAnnotation used in Student Class:
[Table("StudentInfo")]
public class Student
{
    public Student() { }
        
    [Key]
    public int SID { get; set; }

    [Column("Name", TypeName="ntext")]
    [MaxLength(20)]
    public string StudentName { get; set; }

    [NotMapped]
    public int? Age { get; set; }
        
        
    public int StdId { get; set; }

    [ForeignKey("StdId")]
    public virtual Standard Standard { get; set; }
}
        

Fluent API:

Fluent API configuration is applied as EF builds the model from your domain classes You can inject the configurations by overriding the DbContext class' OnModelCreating method as following:
public class SchoolDBContext: DbContext 
{
    public SchoolDBContext(): base("SchoolDBConnectionString") 
    {
    }

    public DbSet<Student> Students { get; set; }
    public DbSet<Standard> Standards { get; set; }
    public DbSet<StudentAddress> StudentAddress { get; set; }
        
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //Configure domain classes using Fluent API here

        base.OnModelCreating(modelBuilder);
    }
}
        
You can use modelBuilder, which is an object of DbModelBuilder class, to configure domain classes.
Let's see DataAnnotation and Fluent API in detail in the next chapter.

EF Code First 7:CF Inheritance

Inheritance Strategy in Code-First

We have seen in the Code First Conventions section that it creates database tables for each concrete domain class. However, You can design your domain classes using inheritance. Object-oriented techniques include "has a" and "is a" relationship, whereas SQL-based relational model has only a "has a" relationship between tables. SQL database management systems don't support type inheritance. So, how would you map object-oriented domain classes with the relational database?
Below are three different approaches to represent an inheritance hierarchy in Code-First:
  • Table per Hierarchy (TPH): This approach suggests one table for the entire class inheritance hierarchy. Table includes discriminator column which distinguishes between inheritance classes. This is a default inheritance mapping strategy in Entity Framework.
  • Table per Type (TPT): This approach suggests a separate table for each domain class.
  • Table per Concrete class (TPC): This approach suggests one table for one concrete class, but not for the abstract class. So, if you inherit the abstract class in multiple concrete classes, then the properties of the abstract class will be part of each table of the concrete class.
We are not going into detail here. Visit the following reference link for more detailed information:
  1. Inheritance with EF Code First: Table per Hierarchy (TPH)
  2. Inheritance with EF Code First: Table per Type (TPT)
  3. Inheritance with EF Code First: Table per Concrete class (TPC)
We have seen default Code First conventions in the previous section. Learn how to configure domain classes in order to override these conventions in the next section.

EF Code First 6:DB Initialization

Database Initialization

We have seen that Code First creates a database automatically in the Simple Code First Example section. Here, we will learn how Code first decides the database name and server while initializing a database.
The following figure shows a database initialization workflow, based on the parameter passed in the base constructor of context class, which is derived from DbContext:
Entity Framework code-first database initialization
As per the above figure, base constructor of the context class can have the following parameter.
  1. No Parameter
  2. Database Name
  3. Connection String Name

No Parameter:

If you do not specify the parameter in the base constructor of the context class then it creates a database in your local SQLEXPRESS server with a name that matches your {Namespace}.{Context class name}. For example, Code First will create a database named SchoolDataLayer.Context for the following context class:
namespace SchoolDataLayer
{
    public class Context: DbContext 
    {
        public Context(): base()
        {
            
        }
    }
}
        

Database Name:

You can also specify the database name as a parameter in a base constructor of the context class. If you specify a database name parameter, then Code First creates a database with the name you specified in the base constructor in the local SQLEXPRESS database server. For example, Code First will create a database named MySchoolDB for the following context class.
namespace SchoolDataLayer
{
    public class Context: DbContext 
    {
        public Context(): base("MySchoolDB") 
        {
                   
        }
    }
}
        

ConnectionString Name:

You can also define connection string in app.config or web.config and specify connection string name starting with "name=" in the base constructor of the context class. Consider the following example where we pass name=SchoolDBConnectionString parameter in the base constructor.
namespace SchoolDataLayer
{
    public class Context: DbContext 
    {
        public SchoolDBContext() : base("name=SchoolDBConnectionString") 
        {
        }
    }
}
        
App.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <connectionStrings>
    <add name="SchoolDBConnectionString" 
    connectionString="Data Source=.;Initial Catalog=SchoolDB-ByConnectionString;Integrated Security=true" 
    providerName="System.Data.SqlClient"/>
    </connectionStrings>
</configuration>
        
In the above context class, we specify a connection string name as a parameter. Please note that connection string name should start with "name=" otherwise, it will consider it as a database name. The database name in the connection string in app.config is SchoolDB-ByConnectionString. Code-First will create a new SchoolDB-ByConnectionString database or use existing SchoolDB-ByConnectionString database at local SQL Server. Make sure that you include providerName = "System.Data.SqlClient" in the connection string.
Thus, Code-First use the base constructor parameter to initialize a database.

EF Code First 5:CF Conventions

Code First Conventions


We have seen how EF Code-First creates DB tables from domain classes in the previous section. Here, we will learn about default Code-First conventions.

What is Convention?

Convention is a set of default rules to automatically configure a conceptual model based on domain class definitions when working with Code-First. Code-First conventions are defined in System.Data.Entity.ModelConfiguration.Conventions namespace.
Let's see an overview of the various Code-First conventions.

Type Discovery:

In the previous section, we created a context class with DbSet properties for the classes that we want to be part of the model. Code-First will create tables for classes included as DbSet properties, as we have seen the previous section. Code-First also includes any referenced types included in these classes, even if the referenced types are defined in a different assembly.
For example, the following Student entity class includes reference of Teacher class. However, context class does not include Teacher as DbSet property.
public class Student
{
    public Student()
    { 
        
    }
    public int StudentID { 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 Teacher Teacher { get; set; }

    public Standard Standard { get; set; }
}

public class Teacher
{
    public Teacher()
    { 
        
    }
    public int TeacherId { get; set; }
    public string TeacherName { get; set; }
}
        
The following is a context class which does not include Teacher as a DbSet property (entity set)
namespace EF_Code_First_Tutorials
{
        
    public class SchoolContext: DbContext 
    {
        public SchoolContext(): base()
        {
            
        }
            
        public DbSet<Student> Students { get; set; }
        public DbSet<Standard> Standards { get; set; }
            
    }
}
        
So, even if Teacher is not included as an entity set in the context class, Code-First will include it in conceptual model and create a DB table for it, as shown below.

Entity Framework code-first example

Code-First also includes derived classes even if the context class only includes base class as a DbSet property.
The conventions for the type discovery are:
  1. Code-First includes types defined as a DbSet property in context class.
  2. Code-First includes reference types included in entity types even if they are defined in different assembly.
  3. Code-First includes derived classes even if only the base class is defined as DbSet property.

Primary Key Convention:

In the previous section, we have seen that Code-First automatically creates a Primary Key in each table. The default convention for primary key is that Code-First would create a primary key for a property if the property name is Id or <class name>Id (NOT case sensitive). The data type of a primary key property can be anything, but if the type of the primary key property is numeric or GUID, it will be configured as an identity column.
If you have defined key property other than Id or <ClassName>Id then ModelValidationException will be thrown. For example, consider the following Standard class:
public class Standard
{
    public Standard()
    { 
        
    }
    public int StdId { get; set; }
    public string StandardName { get; set; }
    
    public IList<Student> Students { get; set; }
   
    }
        
As you can see in the above code, Standard class is defined with StdId key property. Entity Framework will throw the following exception for this.
'System.Data.Entity.ModelConfiguration.ModelValidationException' occurred in EntityFramework.dll
EntityType 'Standard' has no key defined. Define the key for this EntityType.
If you want to define StdId as primary key then you have to use DataAnnotations or Fluent API to configure it as primary key. We will see how to do it later in these tutorials.

Relationship Convention:

Code First infer the relationship between the two entities using navigation property. This navigation property can be simple reference type or collection type. For example, we defined Standard navigation property in Student class and ICollection<Student> navigation property in Standard class. So, Code First automatically created one-to-many relationship between Standards and Students DB table by inserting Standard_StandardId foreign key column in the Students table.
public class Student
{
    public Student()
    { 
        
    }
    public int StudentID { 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; }
        
    //Navigation property
    public Standard Standard { get; set; }
}

public class Standard
{
    public Standard()
    { 
        
    }
    public int StandardId { get; set; }
    public string StandardName { get; set; }
    
    //Collection navigation property
    public IList<Student> Students { get; set; }
   
}
        
The above entities created the following relationship using Standard_StandardId foreign key.

Entity Framework code-first example

Thus, the default code first convention for relationship automatically inserted a foreign key with <navigation property Name>_<primary key property name of navigation property type> e.g. Standard_StandardId.

Foreign key Convention:

We have seen above that Code First automatically inserts a foreign key when it encounters a navigation property. It is recommended to include a foreign key property on the dependent end of a relationship. Consider the following example:
public class Student
{
    public Student()
    { 
        
    }
    public int StudentID { 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; }
        
    //Foreign key for Standard
    public int StandardId { get; set; }

    public Standard Standard { get; set; }
}

public class Standard
{
    public Standard()
    { 
        
    }
    public int StandardId { get; set; }
    public string StandardName { get; set; }
    
    public IList<Student> Students { get; set; }
   
    }
        
As you can see in the above code, Student class includes foreign key StandardId, which is the key property in Standard class. Now, Code First will create StandardId column in Students class instead of Standard_StandardId column, as shown below.

Entity Framework code-first example

Notice that StandardId foreign key is not null in the above figure. This is because int data type is not nullable.
Code First infers the multiplicity of the relationship based on the nullability of the foreign key. If the property is nullable then the relationship is registered as null. Otherwise, the relationship is registered as NOT NULL. Modify data type of StandardId property from int to Nullable<int> in the Student class above to create a nullable foreign key column in the Students table.

Complex type Convention:

Code First creates complex type for the class which does not include key property and also primary key is not registered using DataAnnotation or Fluent API.

Default Code-First Conventions:

The following table lists default code first conventions:
Default Convention ForDescription
Table Name<Entity Class Name> + 's'
EF will create DB table with entity class name suffixed by 's'
Primary key Name1) Id
2) <Entity Class Name> + "Id" (case insensitive)

EF will create primary key column for the property named Id or <Entity Class Name> + "Id" (case insensitive)
Foreign key property NameBy default EF will look for foreign key property with the same name as principal entity primary key name.
If foreign key property does not exists then EF will create FK column in Db table with <Dependent Navigation Property Name> + "_" + <Principal Entity Primary Key Property Name>
e.g. EF will create Standard_StandardId foreign key column into Students table if Student entity does not contain foreignkey property for Standard where Standard contains StandardId
Null columnEF creates null column for all reference type properties and nullable primitive properties.
Not Null ColumnEF creates NotNull columns for PrimaryKey properties and non-nullable value type properties.
DB Columns orderEF will create DB columns same as order of properties in an entity class. However, primary key columns would be moved first.
Properties mapping to DBBy default all properties will map to database. Use [NotMapped] attribute to exclude property or class from DB mapping.
Cascade deleteEnabled By default for all types of relationships.
The following table list C# datatype mapped with SQL datatype and primary key column datatype and length.
C# DataTypeRelated DB Column DataTypePK Column DataType & Length
intintint, Identity column increment by 1
stringnvarchar(Max)nvarchar(128)
decimaldecimal(18,2)decimal(18,2)
floatrealreal
byte[]varbinary(Max)varbinary(128)
datetimedatetimedatetime
boolbitbit
bytetinyinttinyint
shortsmallintsmallint
longbigintbigint
doublefloatfloat
charNo mappingNo mapping
sbyteNo mapping
(throws exception)
No mapping
objectNo mappingNo mapping
This was an overview of code first conventions. These conventions can be overriden using DataAnnotation or Fluent API. Also, you can define custom conventions for your application using Entity Framework 6.0, onwards.

EF Code First 4: CF Example

Simple Code First Example

Let's assume that we want to create a simple application for XYZ School. Users of this School application should be able to add or update Students, Standard (Grade), Teacher, and Course information.
Instead of designing database tables first, let's start creating classes for our school domain, as and when needed. First, we will create two simple Student and Standard classes where every Student is associated with one Standard as shown below.
public class Student
{
    public Student()
    { 
        
    }
    public int StudentID { 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; }
}
        
The Standard (Grade) class should be able to accommodate multiple Students as shown below.
public class Standard
{
    public Standard()
    { 
        
    }
    public int StandardId { get; set; }
    public string StandardName { get; set; }
    
    public ICollection<Student> Students { get; set; }
   
    }
        
Now, we are done with the initial domain classes for our school application. Code-First approach also requires context class which should be derived from DbContext as we have created in the basic tutorials section using Database-First approach. Visit DbContext for more information.
Create a context class as shown below, which derives from DBContext class and exposes DbSet properties for the types that you want to be part of the model, e.g. Student and Standard class, in this case. DbSet is a collection of entity classes (aka entity set), so we have given property name as plural of entity name like Students and Standards.
namespace EF_Code_First_Tutorials
{
        
    public class SchoolContext: DbContext 
    {
        public SchoolContext(): base()
        {
            
        }
            
        public DbSet<Student> Students { get; set; }
        public DbSet<Standard> Standards { get; set; }
            
    }
}
        
Now, we are done with the required classes for the code-first approach. We will now add student using context class as shown below.
class Program
{
    static void Main(string[] args)
    {
     
        using (var ctx = new SchoolContext())
        {
            Student stud = new Student() { StudentName = "New Student" };
        
            ctx.Students.Add(stud);
            ctx.SaveChanges();                
        }
    }
}
        
If you run the application, you will be surprised to see that the application runs successfully and one student is successfully inserted into the database.
But, where is the database and what are the tables and its columns?
This is the beauty of Code-First APIs of Entity Framework. It creates the database based on parameter passed in the base constructor of your context class. Since we have not passed any parameter in the constructor of our context class, it created "EF_Code_First_Tutorials.SchoolContext" database in the local SQLEXPRESS database, as shown below. It also created two tables in this database, Students and Standards tables based on Student and Standard domain classes defined above.

Entity Framework code-first example

As you can see in the above figure, it has created Students and Standards tables and each table contains columns with appropriate datatype and length. The column names and datatype matches with the properties of the respective domain classes. It has also made StudentId and StandardId as PK (primary key) and Standard_StandardId column as FK (foreign key).
This way, without creating a database first, you can start writing an application that will eventually create the database from your domain classes.
You must be wondering how it has created columns with appropriate datatypes and lengh with PK & FK, right? The answer is, using code-first conventions.
Learn code-first conventions in the next section.

EF Code First 3:Setup

Setup Development Environment for EF Code-First

Let's setup the development environment for Code-First before starting on it.
Install the following tools to work with Entity Framework Code-First:
  • .NET Framework 4.5
  • Visual Studio 2012
  • MS SQL Server 2008/2012 Express

Install EF via Nuget:

Here, we will install Entity Framework API (EntityFramework.dll) via NuGet in the VS 2012 console application. (You can install EF via NuGet the same way in any version of Visual Studio.)
First, create the console application. Right click on your project in the solution explorer and select Manage NuGet Packages..
code-first environment setup

This will open Manage NuGet Packages dialogue box. Now, select Online in the left bar and search for EntityFramework as shown below.
Entity Framework install

This will search for all the packages related to Entity Framework. Select EntityFramework and click on Install.
Entity Framework install

Click on the I Accept button in the License Acceptance dialogue box to start the installation.
Entity Framework install

After installation, make sure that the appropriate version of EntityFramework.dll is included in the project.
Entity Framework install

Now, we are ready to use Entity Framework Code-First in our sample console project. Let's start writing our first simple code-first example in the next section.