(Code First ile kalıtım, Hiyerarşik tablolar) Inheritance with Code First TPH-Table per Hierarchy

Neden, nasıl , niçin sorularına sonra uzun bir makale yazağım. şimdilik senaryoya göre ornek bir proje yapacağım..Bilgi vereceğimm Öncelikle modelimize göre POCO classlarımızı hazırlayalım..

 

 
public abstract class User
{
        public int UserId { get; set; }
        public string Ad { get; set; }
        public string Soyad { get; set; }
        public Guid rowGuid { get; set; }
    }

    public class Calisan : User
    {
public int  SSKNo { get; set; }
    }

    public class Ogrenci : User
    {
        public int OkulNo { get; set; }

    }
 
public class OkulumContext : DbContext { public DbSet<User> Users { get; set; } }

Daha Sonra  Bilgi eklemek ve listeleme işlerimini gerçekleştirmek için  aşağıdaki kodlarımızı yazalım..

        static void Ekle()
        {
            Calisan calisan = new Calisan()
            {
                Ad = "erkan", Soyad = "bal", SSKNo = 987878
            };
            Ogrenci ogrenci = new Ogrenci { Ad = "Ayten", Soyad = "Akan", OkulNo = 8978 };
            Ogrenci ogrenci2 = new Ogrenci { Ad = "nisa", Soyad = "Ak", OkulNo = 989 };
            using (OkulumContext db = new OkulumContext())
            {
                db.Users.Add(calisan);
                db.Users.Add(ogrenci);
                db.Users.Add(ogrenci2);
                db.SaveChanges();
            }
        }
    }

 Daha sonra bir foreach dongusu içinde bilgimizi yazdıralım..

static void Main(string[] args)
        {
            Ekle();
            using (OkulumContext db = new OkulumContext())
            {
                Console.WriteLine("Tümünü yazdırıyoruz");
                foreach (var item in db.Users)
                {
                    Console.WriteLine("{0} \t{1}",item.UserId ,item.Ad );
                }
            }
        }

Sql profiller ile  sorgusunu çıktısı inceyelim. 

SELECT 
[Extent1].[Discriminator] AS [Discriminator], 
[Extent1].[UserId] AS [UserId], 
[Extent1].[Ad] AS [Ad], 
[Extent1].[Soyad] AS [Soyad], 
[Extent1].[rowGuid] AS [rowGuid], 
[Extent1].[SSKNo] AS [SSKNo], 
[Extent1].[OkulNo] AS [OkulNo]
FROM [dbo].[Users] AS [Extent1]
WHERE [Extent1].[Discriminator] IN (N'Calisan',N'Ogrenci')



Daha sonra sorgumuzu ben biraz çeşitlendirmek istiyorum. Önceliklle TPH kullanımızın asıl kullanım amacımızı, bizi faydalarını göreceğimiz sorgu türlerinden bahsedelim.

Polymorphic Sorgular

Linq To Entity sorgusuyla veriyi çekelim..

IQueryable<User> linqQuery = from b in db.Users  select b;
                List<User> users2 = linqQuery.ToList();

Aynı işlemi EntitySQL sorgusu ile yazabiliriz. Her iki sogunun SQL çıktısı aynı olacaktır. Yani aşağıdaki sql çıktısı gibi olacaktır.

string eSqlQuery = @"SELECT VAlUE b FROM Users AS b";
ObjectContext objectContext = ((IObjectContextAdapter)db).ObjectContext;
ObjectQuery<User> objectQuery = objectContext.CreateQuery<User>(eSqlQuery);
List<User> users = objectQuery.ToList();

SELECT 
[Extent1].[Discriminator] AS [Discriminator], 
[Extent1].[UserId] AS [UserId], 
[Extent1].[Ad] AS [Ad], 
[Extent1].[Soyad] AS [Soyad], 
[Extent1].[rowGuid] AS [rowGuid], 
[Extent1].[SSKNo] AS [SSKNo], 
[Extent1].[OkulNo] AS [OkulNo]
FROM [dbo].[Users] AS [Extent1]
WHERE [Extent1].[Discriminator] IN (N'Calisan',N'Ogrenci')

Non-polymorphic

Ben burada OfType deyimiyle ornekler vereceğim.

                IQueryable<Calisan> linqQuery = from b in db.Users.OfType<Calisan>()  select b;

                List<Calisan> users2 = linqQuery.ToList();

                foreach (var item in users2)

                {

                    Console.WriteLine("{0} \t{1}", item.Ad, item.SSKNo);

                }

SQl çıktısı aşağıdaki gibi olacaktır.

SELECT 

'0X0X' AS [C1], 

[Extent1].[UserId] AS [UserId], 

[Extent1].[Ad] AS [Ad], 

[Extent1].[Soyad] AS [Soyad], 

[Extent1].[rowGuid] AS [rowGuid], 

[Extent1].[SSKNo] AS [SSKNo]

FROM [dbo].[Users] AS [Extent1]

WHERE [Extent1].[Discriminator] = N'Calisan'

EntitySql ile oftype deyimini kullanmak istersek aşağıdaki gibi bir kod yazmak gerekir. Daha sonrada Tread deyimiyle ibrlikte kullanabiliriz.

                string eSqlQuery = @"SELECT VAlUE b FROM  OFTYPE(Users, TPHSystem.Calisan) AS b";

                ObjectContext objectContext = ((IObjectContextAdapter)db).ObjectContext;

                ObjectQuery<Calisan> objectQuery = objectContext.CreateQuery<Calisan>(eSqlQuery);

                List<Calisan> users2 = objectQuery.ToList(); 

                foreach (var item in users2)

                {

                    Console.WriteLine("{0} \t{1}", item.Ad, item.SSKNo);

                }

SQl Çıktısı

SELECT 

'0X0X' AS [C1], 

[Extent1].[UserId] AS [UserId], 

[Extent1].[Ad] AS [Ad], 

[Extent1].[Soyad] AS [Soyad], 

[Extent1].[rowGuid] AS [rowGuid], 

[Extent1].[SSKNo] AS [SSKNo]

FROM [dbo].[Users] AS [Extent1]

WHERE [Extent1].[Discriminator] = N'Calisan'

 

Sorgumuzu TREAT deyimini kullanarak yapalım..

string sorgum = @"Select value TREAT(b as TPHSystem.Calisan)
                                    FROM Users AS b
                                    WHERE b IS OF(TPHSystem.Calisan)";

SELECT 

'0X0X' AS [C1], 

[Extent1].[UserId] AS [UserId], 

[Extent1].[Ad] AS [Ad], 

[Extent1].[Soyad] AS [Soyad], 

[Extent1].[rowGuid] AS [rowGuid], 

[Extent1].[SSKNo] AS [SSKNo]

FROM [dbo].[Users] AS [Extent1]

WHERE [Extent1].[Discriminator] = N'Calisan'

 

Şimdide fluent api kullanarak tablonun bazı alanlarına ilk değer ataması yapabilriiz. Ayrıca user clasımıza Public bool DegerVarmi gibi bir özellik yazılabilir. Bunu daha onceki çalışmamda yapmıştım..  Şimdi Requires ve HasValue deyimiyle düzenleme yapabilriiz. Boylese o tablodaki kaydın bir çalışanamı yoksa bir ogrenciyemi ait olduğunu anlayabiliriz. Buradan da bu konuyla ilgili geniş bir anlatım bulabilirsiniz.

 

modelBuilder.Entity<User>()
                .Map<Calisan>(t => t.Requires("UserTipi").HasValue(1))
                .Map<Ogrenci>(t => t.Requires("UserTipi").HasValue(2));

 

 Final bölümündeki şunları soylemek yerinde olcaktır. Az kayıti içeren bir kayıtda TPH sistemi kullanılablir. Fakat veri tabanınızda veri miktarı buyukse normalizasyon kuralları geriği TPT(table ğer Type) sisteminin kullanmanız doğru olcaktır. 

 

 

TPHSystem.rar (2,33 mb)

EF CodeFirst TPH TPS kullanımı

Merhaba Arkadaşlar Entitiy Framewrok de Code First yaklaşımında kullandığım TPH ve TPS kullanımına ornek olarak yaptığım ornek yazılım kodlarını cereceğim. Gerekli açıklamaları sonra yazacağım..

 

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;

namespace TPH
{
    public class Program
    {
        static void Main(string[] args)
        {
            using (var context=new TPHC())
            {
                //Product product = new Product { Name = "Elma", Title = "Balık1" };
                //context.Products.Add(product);


                //Gozluk gozluk = new Gozluk { Name = "RyBan", Number = 4, Title = "Gozluk Başlık" };
                //context.Gozlukler.Add(gozluk);


                //Cerceve cerceve = new Cerceve
                //{
                //    Name = "cerceve",
                //    Title = "Cerceveler Başiıl",
                //    Index = "İndexi",
                //    CerceveNumber = 4,
                //    Number = 4,
                //    Category = new Category { Name = "İpli" }
                //};
                //context.Cerceveler.Add(cerceve);
                //context.SaveChanges();

                //var query = from b in context.Products
                //            orderby b.Name
                //            select b;

                //Gozluk gozluk1 = context.Gozlukler.FirstOrDefault(p => p.Id == 3);
                // //Hem Gozluk hemde cercevedeli gozluk ozelliklerini siler.
                //context.Gozlukler.Remove(gozluk1);
                //context.SaveChanges();


                //Console.WriteLine("All blogs in the database:");
                //foreach (var item in query)
                //{
                //    Console.WriteLine(item.Name);
                //}
            //sil();
                 #if true
            
                //BaseClassAbstract temel = new BaseClassAbstract();
                //temel.Number = 45;    
                #endif


            }

    
        }

      private static void sil()
       {
             using (var context=new TPHC())
            {

                Cerceve cerceve = context.Cerceveler.FirstOrDefault(p => p.Id == 4);
                context.Cerceveler.Remove(cerceve);
                context.SaveChanges();
             }
        }
    }
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Title { get; set; }
    }
    public class Gozluk:Product
    {
        public string Index { get; set; }
        public int Number { get; set; }
    }
    public class Cerceve:Gozluk
    {
        public int CerceveNumber { get; set; }
        public  virtual Category Category { get; set; }
    }
    public class Category
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public virtual ICollection<Cerceve> Cerceveler {get;set;}
    }

    public abstract  class BaseClassAbstract
    {
        public int Id { get; set; }
        public int Number { get; set; }

        public BaseClassAbstract()
        {
            // TODO: Complete member initialization
        }
    }

    public class KalitsalOlan : BaseClassAbstract
    {
        public string Name { get; set; }
        public string SurName { get; set; }
    }

    public class TPHC : DbContext
    {
        public DbSet<Product> Products { get; set; }
        public DbSet<Gozluk> Gozlukler { get; set; }
        public DbSet<Cerceve> Cerceveler { get; set; }
        public DbSet<BaseClassAbstract> BaseClasAbstractlar { get; set; }
        public DbSet<KalitsalOlan> KalitsalOlanlar { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Gozluk>().ToTable("Gozlukler");
            modelBuilder.Entity<Cerceve>().ToTable("Cerceveler");
            modelBuilder.Entity<KalitsalOlan>().ToTable("KalitsalOlanlar");
            base.OnModelCreating(modelBuilder);
        }
    }

}

codeFirst.rar (2,33 mb)

 Maskot resmimiz..

The file '/Custom/Widgets/Calendar/widget.cshtml' does not exist.The file '/Custom/Widgets/Category list/widget.cshtml' does not exist.The file '/Custom/Widgets/Tag cloud/widget.cshtml' does not exist.The file '/Custom/Widgets/Page List/widget.cshtml' does not exist.The file '/Custom/Widgets/Month List/widget.cshtml' does not exist.