(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)

Add comment

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.