7 Temmuz 2013 Pazar

Entity Framework - Code First

                Herkese Merhaba, Entity Framework Code First tekniğini göstermek için yazacağım küçük bir örnekle blog yazılarımın ilkine başlıyorum , devamı gelir hayırlısı bakalım :)
 
               Örnekte kategori,ürün ve müşteri sınıfları bulunacak,  Kategori ve Ürün arasında bire çok, Ürün ve Müşteri arasında ise çoka çok ilişki olacak.

              Öncelikle Entity-Framework kütüphanesini projemize dahil etmem gerekiyor, Herhangi bir 3rd parti tool eklemek için önümde iki seçenek var .


              Birinci seçenek; Projenin üzerine sağ tıklayarak Manage Nuget Packages For Solution’u seçerim, açılan pencerede arama kutucuğuna Entity Framework yazarım ve gelen sonuçlardan Entity Framework’ün üzerindeki install butonuna tıklarım;





             Diğer seçenek ise Package Manager Console ile kütüphaneyi projeme dahil etmek .Bunun içine üstteki menüden View => Other Windows => Package Manager Console’u seçerim ve altta açılan console’a Install-Package EntityFramework yazıp Enter' a basarım.





                  Entity Framework Kütüphanesini projeme dahil ettikten sonra sıra geldi classlarımı tanımlamaya ;


 [Table("Urunler")] 

 class Urun 
 { 
    public int Id { get; set; } 
    public string Ad { getset; }
    public Kategori Kategori { getset; } 
    public List<MusteriMusteriler getset; } 
 } 

 [Table("Kategoriler")] 

 class Kategori 
 { 
 public int Id getset; }
 public string Ad getset; }
 public List<Urun> Urunler getset; } 
 } 
 [Table("Musteriler")] 
 class Musteri 
 { 
 public int  Id getset; }
 public string Ad getset; }
 public string Soyad getset; }
 public List<Urun> Urunler getset; } 
 } 


         Başlarına koyduğum attributelerde veritabanında oluşacak olan tabloların isimlerini belirttim, eğer koymasaydım class isimlerine s takısı eklenip tablo ismi belirlenecekti yani kategoris,Musteris,Uruns isminde itici mi itici tablolarım olacaktı. 


         Şimdi Birde DbContext Sınıfından türemiş bir context classına ihtiyacım var(DbContext sınıfı System.Data.Entity namespace’nde yer almakta.) 


class EfContext : DbContext 

 { 

   public DbSet<Urun>Urunler getset; }  

   public DbSet<Kategori> Kategori getset; } 
   public DbSet<Musteri> Musteriler getset; } 

   protected override void OnModelCreating(DbModelBuilder modelBuilder) 

   { 
    modelBuilder.Entity<Urun>().Property(dp => dp.Id).IsRequired(); 
    modelBuilder.Entity<Kategori>().Property(dp => dp.Id).IsRequired();
    modelBuilder.Entity<Kategori>().Property(dp => dp.Ad).HasMaxLength(25);
    modelBuilder.Entity<Urun>().HasMany(p => p.Musteriler)
                                  .WithMany(t => t.Urunler)
                                  .Map(mc => mc.ToTable("MusteriUrun")); 
   } 

   public EfContext() : base(ConfigurationManager.ConnectionStrings["EfDataContext"].Name) 

   {
   

 } 


 Context nesnesinde neler yaptım kısaca bir özetleyeyim;

         
               • Tablo haline getirmek istediğim classları Generic alan Dbset tipinde tanımladım.
         
               • OnModelCreating metodunu override ettim, veritabanına yansımasını istediğim değişiklikleri burada belirtebilirim. Örneğin Kategori ve Urun Id’leri zorunlu alan haline getirdim ve kategori adını 25 karakterle sınırladım . ,Ayrıca Urun ve Müşteri arasındaki çoka çok ilişkiyi burada tanımladım ve bu çoka çok ilişkiden doğacak olan tablonun ismini de burada verdim.
             
                • Son olarak Constructor metodunun base’nde bir connectionString belirledim. Bunun anlamı AppConfig(web projesi yapıyorsanız webconfig) dosyasındaki “EfDataContext” isminde tanımlanmış connection string'i bul ve veritabanına bu bilgiler ile bağlan. AppConfig dosyasına adı “EfDataContext” olan connection stringide ekledim ;


                    Burda klasik connection string ten farklı olarak MultipleActiveResultSets=True yaptım. Bunun nedeni aynı connectionda birden çok sorguyu paralel olarak yapılmasını sağlamak.


                    İşim hemen hemen bitti, main metoduna da şunları yazdım mı tamamdır.


 static void Main() 

 { 
   EfContext context = new EfContext(); 
   context.Kategori.Add(new Kategori() {Ad = "KategoriAd"}); 
   context.SaveChanges(); 
 }

                Context nesnesini üretip bir kez veritabanı bağlantılı bir iş yaptırmam sql server da connectionstring yazarken belirttiğimiz isimde bir veritabanı oluşturulmasına yeter. Veritabanını oluşturdum rahat rahat select,create ,update ,delete işlemlerini yapabiliyorum. Peki ya bir değişiklik yapmak istediğim ne olacak? şimdi musteri classına bir de email property’si ekleyip çalıştırayım ve aşağıdaki hatayı alayım:)




           Yani Diyor ki, Sen yaptığın değişiklikleri veritabanına anlatmadın ki şimdi ben senin context nesnen ile veritabanını nasıl eşleyeyim.

       
          Context’in constructor metodunda Database nesnesinin SetInitializer metoduna parametre olarak dropCreateDatabaseIfModelChanges nesnesini vererek veritabanını ilgilendiren herhangi bir değişiklik yapıldığı takdirde veritabanının silinip yeni baştan inşa edilmesini sağlayabilirim.     

Database.SetInitializer(new DropCreateDatabaseIfModelChanges<EfContext>());


          Yok ben değişiklik yapmasamda her çalıştırdığımda veritabanı silinip yeniden yaratılsın diyorsam (bunu neden yaparım bilmiyorum artık ne çeşit fantezilerim varsa gerçi programlama dünyası belli olmaz :)) DropCreateDatabaseAlways nesnesini metoda veririm.             
       
 Database.SetInitializer(new DropCreateDatabaseAlways<EfContext>());
            
          Peki ben hem contextim değişsin hemde veritabanındaki verilerim silinmesin istiyorum yani yaptığım değişikliklerde veritabanım silinip yenisi yaratılmasın ben oraya veri giriyorum her seferinde data girmekle uğraşamam bi yer değiştiriyorum diye neden bütün veritabanı sıfırlansın diyorsan;

Çare Migration :)

1 yorum: