Entity Framework, Code First Complex Type (Komplesk, karışık tipler)

Merhaba arkadaşlar ben hemen makalenin konusu olan EntityFramework  Comple Type'' ları anlatıyor olcağım. Aslından bu makaleyi TPC,TPS,TPC tipleril birleştirerek anlatmak istiyordum.Konu basit fakat geniş olduğu için tek makelede anlatmaya çalışacağım.. Makeleyi anlamınız için EntityFramwork ve c#, birazda code first hakkında bilgi sahibi olmanız gerekmekte. Aslında bize bu tipi kullanmanın en buyuk faydalarından biri yazım kolaylığı olması veri tabamızın düzgün, kodların  clean code olması açısından önemli.  

Senaryomuza göre basit bir  POCO(Plain Old CLR Objects)  classı yazalım.. Porje hazırlerken consoleaplication uyglaması yaratıyorum.. Nuget Console uygulması yüklenmiş vir studyo 2010 veya studio 2012 programı ile EntityFramworkü projenin üzerinda sağ tuşa basarak veya nuget cosolle den aşağıdaki kodu yazarak yükleyebilirim.

 PM> Install-Package EntityFramework -Version 5.0.0 

 

 

public class Personel
    {
        public int PersonelId { get; set; }
        public int SGKNo { get; set; }
        public string Ad{get;set;}
        public string Soyad { get; set; }
        public string Cadde { get; set; }
        public string  Mahalle { get; set; }
        public string PostaKodu { get; set; }
    }



Bole bir tanımlamada göreceğiniz gibi gereksiz tanımlamalar mevcuttur.. Bunu daha düzgün hale getirelim.. Asıl amaç Null(Boş) değer içerebilecek alanları kök tablodan ayırmaktır.

public class Personel
    {
        public int PersonelId { get; set; }
        public int SGKNo { get; set; }
        public string Ad{get;set;}
        public string Soyad { get; set; }
    }

    public class Adres 
    {
        public int AdresId { get; set; }
        public string Cadde { get; set; }
        public string Mahalle { get; set; }
        public string KapiNo { get; set; }
        public string PostaKodu { get; set; }
    }

Halinde yazalım. Burada unutmamaız gereken bir kural var. complex Tipler Key içermezler. O yüzden AdresId satırını açıklama satırına dönüştürelim..

//public int AdresId { get; set; }

Complex Tip tanımlama Kuralları(convention Rule)
Şimdi Code first yaklaşımında convention kuralları denen bir kurallar bütünü bulunmakta. Mesala Adres sınıfında public int Id{get;set;} veya public int AdresId{get;set;} yapmam, convention kurallarına göre o alanın key olması sağlamakta.

Commplex Type Convention Kuralları
1. Key anahtarına sahip olan bir özellik içermemeli
2. Basit tipler olmalı
3. Başka bir clasın içnede kullanırken Collection haline dönüştürmemiz gerekir. Mesala List<Adres>

Ayrıca personel tanımlarken adress nesnesi balatılmalı veya
public class Personel
    {
        public Personel()
        {
            Fatura = new Adres();
        }
modelin oluştuğu yerde fatura bilgileri girilmelidir. Ben Aşağıdaki gibi her iki yöntemide seçtim..

using (DataBaseContext  db=new DataBaseContext() ) {
            new List<Personel> { 
                new Personel{ Ad="kemal", Soyad="Yürek",  SGKNo=897897897, 
                    Fatura= new Adres{Cadde="Yeni Cadde.", KapiNo="54", PostaKodu="13212"}}
               ,new Personel{Ad="Tarkan", Soyad="Ay",  SGKNo=980989089,
               Fatura= new Adres{Cadde="Yeni Cadde.", PostaKodu="13212"}}
            }.ForEach(t=>db.Personeller.Add(t));   //değişiklik olsun diye fluent api kullanarak ekledim..

            db.SaveChanges();
            }
          
        }

Görüldüğü gibi Aşağıdaki veritabanı oluşmaktadır.
 

 

 

İllaki adres poco clasında AdresId isimli bir Key özellikli bir alan olması gerekiyorsa poco clasından başında ComplexType attribütünü(nitelik) kullanabilirsiiniz. Aşağıdaki gibi kullanılabilir.

   [ComplexType]
    public class Adres 
    {
        public int AdresId { get; set; }
        public string Cadde { get; set; }
        public string Mahalle { get; set; }
        public string KapiNo { get; set; }
        public string PostaKodu { get; set; }
    }

 

 

Görüldüğü gibi AdresId de veritabanızmızda görüncektir.

 

[ComplexType] abtiribute Data Annotions kullanmak için yerine projeye  aşağıdaki satırı eklemek zorundasınız. 

using System.ComponentModel.DataAnnotations.Schema; 
veya bu işlemi aşağıdaki gibi Fluent Api kullanarakda belitebilirsiniz.
public class DataBaseContext : DbContext
    {
        public DbSet<Personel> Personeller { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.ComplexType<Adres>(); ///burada belirttim.
        }
    }

Projenin tamamını aşağıdaki gibi yapalım. Ayrıcı model üzerinde yaptığınız değişiklikler migrations işlemi yapacaksınız, veya veritabanınıda çalıştırmadan once silebilir. Üçüncü bir yöntem olarak Database.SetInitializer(new ProjeInit()); yöntemini kullanabilirsiniz.
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;

namespace ComplexType
{
    class Program
    {
        static void Main(string[] args)
        {
            Database.SetInitializer(new ProjeInit());
            using (DataBaseContext db = new DataBaseContext())
            {
                new List<Personel> { 
                new Personel{ Ad="kemal", Soyad="Yürek",  SGKNo=897897897, 
                    Fatura= new Adres{Cadde="Yeni Cadde.", KapiNo="54", PostaKodu="13212"}}
               ,new Personel{Ad="Tarkan", Soyad="Ay",  SGKNo=980989089,
               Fatura= new Adres{Cadde="Yeni Cadde.", PostaKodu="13212"}}
            }.ForEach(t => db.Personeller.Add(t));   //değişiklik olsun diye fluent api kullanarak ekledim..
                db.SaveChanges();

                Adres adres = new Adres { Cadde = "yeni cd", Mahalle = "Yeni mahalle", KapiNo = "87", PostaKodu = "8789" };
                Personel personlim = new Personel { Ad = "Mahmut", SGKNo = 89789, Soyad = "Bal",
                                                    Kargo = new Adres { Cadde = "Eski Cadde.", KapiNo = "54", PostaKodu = "13212" },
                                                    Fatura = new Adres { Cadde = "Orta Cadde.", KapiNo = "54", PostaKodu = "13212" }
                };
                db.Personeller.Add(personlim);
                db.SaveChanges();
                foreach (var item in db.Personeller)
                {
                    //verileri yazalımm.
                    Console.WriteLine("{0}\t{1}\t{2}\t{3}", item.PersonelId, item.Ad, item.Fatura.Cadde, item.Fatura.PostaKodu);
                }
            }
                
        }
    }

    public class Personel
    {
        public Personel()
        {
            Fatura = new Adres();
            Kargo= new Adres();
        }
        public int PersonelId { get; set; }
        public int SGKNo { get; set; }
        public string Ad{get;set;}
        public string Soyad { get; set; }
        public Adres Fatura { get; set; }
        public Adres Kargo { get; set; }
    }


    //[ComplexType]
    public class Adres 
    {
        public int AdresId { get; set; }
        public string Cadde { get; set; }
        public string Mahalle { get; set; }
        public string KapiNo { get; set; }
        public string PostaKodu { get; set; }
    }
    public class DataBaseContext : DbContext
    {
        public DbSet<Personel> Personeller { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {

            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); //isimlerdirme kurallarını devre dışı bıraktım..
            modelBuilder.ComplexType<Adres>();
        }
    }


    class ProjeInit : DropCreateDatabaseAlways<DataBaseContext>
    {
        protected override void Seed(DataBaseContext context)
        {
            base.Seed(context);
        }
    }
}

Örneğimizi ben biraz daha karışık tipler kullanarak ukardaki gibi son aşamaya getirdim. ve çalıştırdım.. hale gitirdim.

Ayrıca Lİnq ile veri çekme kodları da yazdım. 

 

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Linq;

namespace ComplexType
{
    class Program
    {
        static void Main(string[] args)
        {
            Database.SetInitializer(new ProjeInit());
            using (DataBaseContext db = new DataBaseContext())
            {
                new List<Personel> { 
                new Personel{ Ad="kemal", Soyad="Yürek",  SGKNo=897897897, 
                    Fatura= new Adres{Cadde="Yeni Cadde.", KapiNo="54", PostaKodu="13212"}}
               ,new Personel{Ad="Tarkan", Soyad="Ay",  SGKNo=980989089,
               Fatura= new Adres{Cadde="Yeni Cadde.", PostaKodu="4444"}}
            }.ForEach(t => db.Personeller.Add(t));   //değişiklik olsun diye fluent api kullanarak ekledim..
                db.SaveChanges();

                Adres adres = new Adres { Cadde = "yeni cd", Mahalle = "Yeni mahalle", KapiNo = "87", PostaKodu = "8789" };
                Personel personlim = new Personel { Ad = "Mahmut", SGKNo = 89789, Soyad = "Bal",
                                                    Kargo = new Adres { Cadde = "Eski Cadde.", KapiNo = "54", PostaKodu = "13212" },
                                                    Fatura = new Adres { Cadde = "Orta Cadde.", KapiNo = "54", PostaKodu = "13212" }
                };
                db.Personeller.Add(personlim);
                db.SaveChanges();
                foreach (var item in db.Personeller)
                {
                    //verileri yazalımm.
                    Console.WriteLine("{0}\t{1}\t{2}\t{3}", item.PersonelId, item.Ad, item.Fatura.Cadde, item.Fatura.PostaKodu);
                }

                //LinQ kullanarak Veri çekme örneği
                var personel = from b in db.Personeller
                               where b.Fatura.PostaKodu=="4444"
                               select b;


                foreach (var item in personel )
                {
                    //verileri yazalımm.
                    Console.WriteLine("\r\n{0}\t{1}\t{2}\t{3}", item.PersonelId, item.Ad, item.Fatura.Cadde, item.Fatura.PostaKodu);
                }

            }
                
        }
    }

    public class Personel
    {
        public Personel()
        {
            Fatura = new Adres();
            Kargo= new Adres();
            Bilgi = new PersonelBilgileri
            {
                Boy = new Olculer(),
                Kilo = new Olculer()
            }; 
        }
        public int PersonelId { get; set; }
        public int SGKNo { get; set; }
        public string Ad{get;set;}
        public string Soyad { get; set; }
        public Adres Fatura { get; set; }
        public Adres Kargo { get; set; }
        public PersonelBilgileri  Bilgi { get; set; }
    }

    public class Olculer
    {
        public decimal deger { get; set; }
        public string birim { get; set; }
    }



    public class PersonelBilgileri
    {

        //PersonelBilgileri burada complex tiptir.
        //PersonelBilgileri has no ke, yani key tanımlanmamış hatası alabilriiz.
        //[ComplexType] Data Annations burada devreye girmeyeceğin için veb 
        //Fluent Api kullanarak bu tablonun complext tip olduğunu belirttim 
        //ve çalıştı. Compxlex tipler muhahkak başlatılmalıdır. 
        //Hasvalue gibi bir okunur özellik yaratarak bunun bir değer içerip içermediğini kontro edebilriiz. 
        public Olculer  Boy { get; set; }
        public Olculer Kilo { get; set; }

        public bool HasValue
        {
            get
            {
                return ((Boy != null) || Kilo != null);
            }
        }
    }

    //[ComplexType]
    public class Adres 
    {
        public int AdresId { get; set; }
        public string Cadde { get; set; }
        public string Mahalle { get; set; }
        public string KapiNo { get; set; }
        public string PostaKodu { get; set; }
    }
    public class DataBaseContext : DbContext
    {
        public DbSet<Personel> Personeller { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {

            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); //isimlerdirme kurallarını devre dışı bıraktım..
            modelBuilder.ComplexType<Adres>();
            modelBuilder.ComplexType<PersonelBilgileri>();
        }
    }


    class ProjeInit : DropCreateDatabaseAlways<DataBaseContext>
    {
        protected override void Seed(DataBaseContext context)
        {
            base.Seed(context);
        }
    }
}

 

Bir sonraki makalede görüşmek üzere hoşçakalın..

Comments (2) -

Bülent ERDEM
9/6/2015 10:04:01 AM #

Çok güzel makale ellerinize sağlık.

ErkanYurek
5/28/2019 5:09:26 AM #

Thank you

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.