In this article we will learn to tackle inheritance in
Entity Framework. If still you are not clear with the aim of the article, below
few limes is for you.
We know that inheritance is a beautiful concept in Object
Oriented programming and it gives the concept of re-usability, which is one of
the important practices of software design principal. Ok, we will implement
inheritance in class level, that’s fine but how it will implement in DB level? As rule, we know derive class contains all
property of base class, so is derive class table will contains all property of
base class table?
We will learn that stuff in this along with next two
articles. There are three approaches in Entity Framework level to tackle
inheritance in code level.
·
Table per hierarchy
·
Table per type
·
Table per concrete class
In this article we will understand Table per Hierarchy. We
know that inheritance is nothing but hierarchical concept, where one class is
derived from another class. It forms a
tree stricture by classes and subclasses. Table per hierarchy concept says that, one
table will get create per hierarchy.
For example, If
there is class A and class B is derived from class A , then for that hierarchy
only one table will get create in database.
So, the basic concept is for a single hierarchy, there
will be one table. Have a look on below code.
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace CodeFirst
{
public class Person
{
[Key]
public int PersonId { get; set; }
[Required]
[MaxLength(10)]
public string Name { get; set; }
public string surname { get; set; }
}
public enum FriendType
{
Close,
NotClose,
FamilyFriend
}
public class Friend : Person
{
public Int32 Person { get; set; }
public FriendType FriendType { get; set; }
}
public class TestContext : DbContext
{
public TestContext()
: base("DBConnectionString")
{
}
public DbSet<Person> Person { get; set; }
}
}
In this example , we
have implemented one hierarchy by inheriting Person class within Friend class.
Entity Framework is smart enough to implement Table per hierarchy without any
external instruction.
Now, have a look on TestContext class, we are passing
connection string through constructor , the connection string need to configure
in web.config file.
Within the class, we
are initiating only Person class not Friend class, this is the beauty of Entity
Framework, If we populate base class, then automatically the related derive
class will also configure in single table.
Here is the connection
string in web.config file for this example.
<connectionStrings>
<add name="DBConnectionString"
connectionString="Data Source=SERVERNAME;Initial Catalog=PersonDB;Integrated
Security=true"
providerName="System.Data.SqlClient"/>
</connectionStrings>
Once we run the application, we will see that the database
is created and table has generated like below.
Now, if we closely look on table stricture, we will see one
Discriminator column , why the extra column created ? We did not implement it in
code.
Entity Framework has smartly created that field to
distinguish between tables. The concept is like this, both Person object and
Friend object will get save in single table, how we will distinguish them? How
we will know whether the particular row containing data for Person object or
Friend object. Tow distinguish between
them, the Discriminator column has introduced.
Here is the code where we are saving object of Person class.
static void Main(string[] args)
{
using (var ctx = new TestContext())
{
//Save
Object of Person table.
ctx.Person.Add(new Person { Name = "Sourav",
surname = "Kayal" });
ctx.SaveChanges();
}
}
Have a look on table data, we are seeing that “Person” has
saved in Discriminator column value, so the record contains objet of Person
class.
Now, we will save object of Friend class in same table, have
a look on below code.
static void Main(string[] args)
{
using (var ctx = new TestContext())
{
//Save
Object of Person table.
ctx.Person.Add(new Friend { Name = "Foo",
surname = "Bar" ,PersonId = 1,FriendType =FriendType.Close});
ctx.SaveChanges();
}
}
Here the data has saved in table and the value for
Discriminator column is Friend.
Customize the “Discriminator”
column
You may think that , is it possible to change the default
“Discriminator” column name ? or change it’s value ? Yes, it’s possible , Using
Fluent API, we can do it. Have a look on modified code.
public class TestContext : DbContext
{
public TestContext()
: base("DBConnectionString")
{
}
public DbSet<Person> Person { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.Map<Friend>(m =>
m.Requires("ObjectType").HasValue("FriendType"));
modelBuilder.Entity<Person>()
.Map<Person>(m =>
m.Requires("ObjectType").HasValue("PersonType"));
}
}
Now, when we will save data of some Object , for example
Friend Object, it will save value “Friend Type” unlike “Friend” in previous
example. Let’s try to save data using below code.
static void Main(string[] args)
{
using (var ctx = new TestContext())
{
ctx.Person.Add(new Friend { Name = "Foo",
surname = "Bar" ,PersonId = 1,FriendType =FriendType.Close});
ctx.SaveChanges();
}
}
Have a look on database structure. We are seeing that “FriendType” has saved in
table because we have save object of Friend class.
Now, we will try to save object of Person class in table ,
here is sample code.
static void Main(string[] args)
{
using (var ctx = new TestContext())
{
ctx.Person.Add(new Person { Name = "Ram",
surname = "Kumar" });
ctx.SaveChanges();
}
}
Now, the value is “Person Type” in table.
Fine, we have learned the concept of table creation and
concept of Discriminator column, now we will learn to fetch data from the
table.
To fetch data from such table, we can use both polymorphic
and non-polymorphic query. Just have try both of them
Polymorphic –Query
As the concept, it will pull all related hierarchical data
in single query. Here we are pulling all data related to Person Object, now, as
Friend is derived from Person, so Friend information too pulling automatically.
Here is sample code.
using (var ctx = new TestContext())
{
var data = from tab in ctx.Person select tab;
List<Person> persons= data.ToList();
}
Just look that both two rose has fetched from table, so, we
are getting both Friend and Person object.
Non-Polymorphic Query
In this query we will pull particular column value, here are
pulling “Friend” object only.
using (var ctx = new TestContext())
{
//Get
All Friend From Person Table
var data = from tab in ctx.Person.OfType<Friend>() select tab;
List<Friend> persons = data.ToList();
}
And we are getting only single object.
Border line:
We have learned to implement Table per Hierarchy concept to
implement inheritance in Entity Framework, hope this article will help you to
go ahead one step towards Entity Framework learning. In coming article we will
understand two more inheritance strategy in Entity Framework environment.
Man u r awesome.
ReplyDeleteThanks girish
ReplyDeleteGreat reading your posst
ReplyDelete