Entity Framework 6.0 ile Veri tabanı Tablolarındaki Ortak Kolonları Güncelleme

Geliştirmiş olduğunuz programlarınıza ait veri tabanlarında mutlaka aşağıdaki diyagramdaki gibi bir yapı geliştirmiş veya karşılaşmışsınızdır. Burada tablo isimleri veya aralarındaki bağlantı değil. Tablolarda bulunan ortak kolonları gözden kaçırmamanızı istiyorum. Basit olarak iki adet ortak kolonu 3 farklı tabloya ekledim. Bu kolonlar “lud(last updated date – son güncellenme tarihi)” ve “cdate(create date – oluşturulma tarihi)” isimli kolonlardır. Tabii ki ben konuyu anlatmak için sadece bu iki kolonu ekledim.

Normalde; LastModifiedBy(Son güncelleyen) , LastModifiedAt(Son güncelleme tarihi), CreatedBy(Oluşturan) ve CreatedAt(oluşturulma tarihi) şeklinde 4 adet kolonu barındırması daha doğru olacaktır.

Entity Framework 6.0 ile Veri tabanı Tablolarındaki Ortak Kolonları Güncelleme

 

kmb-udemy-reklam

Basit bir form üzerinden örneğimizi yapalım.

Entity Framework 6.0 ile Veri tabanı Tablolarındaki Ortak Kolonları Güncelleme

Ekranda gördüğünüz 3 listbox’a veri tabanındaki uygun verileri dolduruyorum. Listbox’ların üstündeki GroupBox başlıklarından hangisine hangi verinin dolduğunu anlayabilirsiniz. Tabii burada Telefon Numaraları isimli listbox’ın verisi Kişiler isimli listbox’dan seçilen kişi olduğunda doluyor. Her listbox’ın üstünde bulunan “Yeni” ikonu ile yeni kayıt ekleme işlemini, “Kaydet” ikonu ile de kayıtları güncelleme işlemini ilgili tabloya yapıyorum.

Buradaki amaç yeni kayıt ekleme ve güncelleme işlemlerinde ortak olan kolonları(lud ve cdate) otomatik olarak yazacağımız merkezi bir kod ile güncelleme, sürekli olarak işlem yapılan tablolarda bu kolonları işlemek içinde kod yazmak çok mantıklı değil.. Fakat tabii ki özel işlemler söz konusu ise yazılabilir.

Örnek veri tabanı script’ini yazının sonunda bulabilirsiniz. Sql script’i veri tabanınızda çalıştırdığınızda veri tabanı, tabloları ve örnek veriler yüklenecektir. Ardından bir windows form application (C#) projesi açarak yukarıdaki görünümde bir form tasarlayabilirsiniz.

Projenize ADO.NET Entity Data Model ekleyerek veri tabanına bağlanıp gerekli tabloları seçiniz. Ben isim olarak “TestDbModel” verdim.

Entity Framework 6.0 ile Veri tabanı Tablolarındaki Ortak Kolonları Güncelleme

Bu işleminde ardından form’un arkasına yazacağımız kodlar şu şekildedir.

public partial class Form1 : Form
{
    private TestDbEntities Entity = new TestDbEntities();
    private Random Rnd = new Random();

    public Form1()
    {
        InitializeComponent();

        this.btnNewKisi.Click += btnNewKisi_Click;
        this.btnSaveKisi.Click += btnSaveKisi_Click;
        this.btnNewTelNo.Click += btnNewTelNo_Click;
        this.btnSaveTelNo.Click += btnSaveTelNo_Click;
        this.btnNewNot.Click += btnNewNot_Click;
        this.btnSaveNot.Click += btnSaveNot_Click;
        this.lstKisiler.SelectedIndexChanged += lstKisiler_SelectedIndexChanged;

    }

    private void Form1_Load(object sender, EventArgs e)
    {
        this.LoadKullanicilar();
        this.LoadNotlar();
    }

    private void btnNewKisi_Click(object sender, EventArgs e)
    {
        // Yeni kullanıcı kayıdı veritabanına yapılır.
        int kno = this.lstKisiler.Items.Count + 1;

        Kullanici k = new Kullanici();
        k.ad = "Kullanıcı-" + kno.ToString();
        k.soyad = "Kullanıcı-" + kno.ToString();

        // Dikkat ederseniz burada lud ve cdate kolonlarına 
        // bir veri yazma işlemi yoktur.

        this.Entity.Kullanici.Add(k);
        this.Entity.SaveChanges();

        this.LoadKullanicilar();
    }

    private void btnSaveKisi_Click(object sender, EventArgs e)
    {
        if (this.lstKisiler.SelectedIndex > -1)
        {
            // Eğer kullanıcı seçilmiş ise ad ve soyadı sonuna x yazılır.
            Kullanici k = this.lstKisiler.SelectedItem as Kullanici;

            k.ad += "x";
            k.soyad += "y";

            // Dikkat ederseniz burada lud ve cdate kolonlarına 
            // bir veri yazma işlemi yoktur.

            this.Entity.SaveChanges();
            this.LoadKullanicilar();
        }
    }

    private void btnNewTelNo_Click(object sender, EventArgs e)
    {
        if (this.lstKisiler.SelectedIndex > -1)
        {
            // Eğer kullanıcı seçilmiş ise yeni telefon numarası
            // rastgele oluşturularak eklenir.
            Kullanici k = this.lstKisiler.SelectedItem as Kullanici;

            TelNo t = new TelNo();
            t.KullaniciID = k.id;
            t.TelNo1 = this.Rnd.Next(100, 999).ToString();

            // Dikkat ederseniz burada lud ve cdate kolonlarına 
            // bir veri yazma işlemi yoktur.

            this.Entity.TelNo.Add(t);
            this.Entity.SaveChanges();

            this.LoadTelNolar();
        }
    }

    private void btnSaveTelNo_Click(object sender, EventArgs e)
    {
        if (this.lstTelNolar.SelectedIndex > -1)
        {
            // Eğer telefon numarası seçilmiş ise seçili numara
            // sonuna "0" eklenerek güncellenir.
            TelNo t = this.lstTelNolar.SelectedItem as TelNo;

            t.TelNo1 += "0";

            // Dikkat ederseniz burada lud ve cdate kolonlarına 
            // bir veri yazma işlemi yoktur.

            this.Entity.SaveChanges();
            this.LoadTelNolar();
        }
    }

    private void btnNewNot_Click(object sender, EventArgs e)
    {
        // Yeni bir not oluşturularak kaydedilir.
        Note n = new Note();
        n.NoteVal = this.Rnd.Next(10, 99);

        // Dikkat ederseniz burada lud ve cdate kolonlarına 
        // bir veri yazma işlemi yoktur.

        this.Entity.Note.Add(n);
        this.Entity.SaveChanges();

        this.LoadNotlar();
    }

    private void btnSaveNot_Click(object sender, EventArgs e)
    {
        if (this.lstNotlar.SelectedIndex > -1)
        {
            // Seçili not değeri +/- 3 olarak güncellenir.
            Note n = this.lstNotlar.SelectedItem as Note;

            if (n.NoteVal < 98)
                n.NoteVal += 3;
            else
                n.NoteVal -= 3;

            // Dikkat ederseniz burada lud ve cdate kolonlarına 
            // bir veri yazma işlemi yoktur.

            this.Entity.SaveChanges();
            this.LoadNotlar();
        }
    }

    private void lstKisiler_SelectedIndexChanged(object sender, EventArgs e)
    {
        this.LoadTelNolar();
    }



    private void LoadNotlar()
    {
        this.lstNotlar.DisplayMember = "NoteVal";
        this.lstNotlar.ValueMember = "ID";
        this.lstNotlar.DataSource = Entity.Note.ToList();
    }

    private void LoadKullanicilar()
    {
        this.lstKisiler.DisplayMember = "ad";
        this.lstKisiler.ValueMember = "id";
        this.lstKisiler.DataSource = Entity.Kullanici.ToList();
    }

    private void LoadTelNolar()
    {
        if (this.lstKisiler.SelectedIndex > -1)
        {
            Kullanici k = this.lstKisiler.SelectedItem as Kullanici;

            this.lstTelNolar.DisplayMember = "TelNo1";
            this.lstTelNolar.ValueMember = "ID";
            this.lstTelNolar.DataSource = Entity.TelNo.Where(x => x.KullaniciID == k.id).ToList();
        }
    }
}

Peki en önemli kısma geldik. EF ‘ün “SaveChanges“ metodu çalıştırıldığında yeni eklenmiş entity nesnelerinde ve Güncelleme yapılan entity nesnelerinde gerekli kolonları işlemeliyiz. Tablo ayrımı olmadan..! Kodlar üzerinde gerekli açıklamaları yaptım ama burada da kısaca değinmek istiyorum.

TestDbEntities” class’ımız bir partial class olduğu için aynı isimli ve partial ifadesi geçen bir class oluşturuyoruz. Böylece aslında “TestDbEntities” class’ının devamını yazmaya başlamış oluyoruz. Ardından “SaveChanges” metodunu “Override” ederek eziyoruz ve save işlemi öncesine kendi kodlarımızı yazıyoruz. Bu kodlarda insert ve update edilecek entity nesnelerini elde edip, insert edilecekler de “cdate” kolonunu ve “lud” kolonunu, update edilecek entity nesnelerinde ise sadece “lud” kolonunu işleyecek şekilde kodlarımızı yazıyoruz. Farklı iki şekilde yazdım. İki şekilde de uygundur hangisi kolayınıza geliyorsa onu kullanabilirsiniz.

public partial class TestDbEntities
{
    public override int SaveChanges()
    {
        // Added(insert edilecekler) ve Modified(update edilecekler) elde edilir.
        List<DbEntityEntry> changesList =
            this.ChangeTracker.Entries().Where(
            x => x.State == System.Data.Entity.EntityState.Added ||
                x.State == System.Data.Entity.EntityState.Modified).ToList();

        foreach (DbEntityEntry entry in changesList)
        {
            // Eğer insert edilecek ise cdate özelliği de yazılır.
            if (entry.State == System.Data.Entity.EntityState.Added)
            {
                // 1. yol : entry.CurrentValues özelliği ise işlem yapma..
                if (entry.CurrentValues["cdate"] != null)
                    entry.CurrentValues["cdate"] = DateTime.Now;
            }

            // ister update ister insert olsun lud yazılır.
            // 2. yol : entry.Property özelliği ise işlem yapma..
            if (entry.Property("lud") != null)
                entry.Property("lud").CurrentValue = DateTime.Now;
        }

        // Savechanges metodumuz kaldığı yerden devam ediyor.
        return base.SaveChanges();
    }
}

Görüldüğü üzere gerekli “lud” ve “cdate” verileri yazılmış. Yeni veriler eklenmiş ve güncellenecek olanlar güncellenmiştir.

Entity Framework 6.0 ile Veri tabanı Tablolarındaki Ortak Kolonları Güncelleme

 

Proje dosyaları için tıklayınız..

kmb-udemy-reklam

Reklamlar

Visual Studio 2012’de Entity Framework CodeGenerationStrategy ve WCF Sorunu

Visual Studio 2012 ile çalışırken EntityFramework ve WCF ‘i bir arada kullanıyorsanız muhtemelen birkaç sorun ile karşılaşacaksınız. Ben bu sorun ile silverlight uygulaması geliştirirken bir şekilde tanışmış oldum. Öncelikle senaryomuzdan bahsetmek istiyorum.

Sorunun Tespiti;

Visual Studio 2012 ile bir silverlight uygulaması geliştirmek için gerekli projeyi oluşturdum. Projeyi .Net Framework 4.0 ve Silverlight 5 versiyonlarını kullanarak geliştirmek üzere ön ayarlamalarını yaptıktan sonra projemiz planlandığı gibi visual studio 2012 ile oluşturuluyor. Elimizde ilişkili tablolar bulunan bir SQL veritabanı mevcut. Ardından ASP.NET projemize ADO.NET Entity Data Model (EF) ekliyoruz. Modelimiz veritabanından ilişkilendirilmiş tablolarımızı okuyarak ilgili kod üretme işlemini gerçekleştiriyor. ASP.NET projemize silverlight uygulamamız ile veri alışverişinde bulunmak üzere bir WCF servisi ekliyoruz. İlişkili herhangi bir tablodan veri okuyan basit bir metot ekliyoruz. Ardından silverlight uygulamamıza WCF servisimizi Service Reference olarak ekliyoruz. Silverlight uygulamamızdan ilgili metodu çağırdığımız da servis cevabı alınamadığına dair bir hata ile karşılaşacağız. (Bu hata ilişkisiz bir tablodan veri okurken değil ilişkisi bulunan bir tablodan veri okurken meydana geliyor.)

Projenin Oluşturulması

Silverlight Projesinin Ayarlanması

ADO.NET Entity Data Model Eklenmesi

WCF Servisinin Eklenmesi

Silverlight Uygulamasına WCF Servis Eklenmesi ve Kodlama

Silverlight Uygulamasının Çalıştırılması

The remote server returned an error: NotFound.

Oluşan hata şekilden de görüldüğü gibidir. “The remote server returned an error: NotFound.

 

Sorunun Çözümü;

Yukarıda anlattığım  proje adımlarını Visual Studio 2010 ile gerçekleştirdiğinizde böyle bir sorun ile karşılaşmıyorsunuz. Projeniz sağlıklı bir şekilde çalışıyor.

  1. İlk düşündüğüm, Visual Studio 2012 ile gelen Entity Framework ‘ün versiyonunun yükselmiş olmasından kaynaklandığını düşündüm. Visual Studio 2012 üzerindeki projemdeki Entity Framework versiyonunu düşürmeye çalıştım. Bu sonucu etkilemedi.
  2. İkinci düşündüğüm, WCF servisi için yeni bir güncelleme  ya da versiyon yayınlanmış olabileceği ve benim bunu yüklemememden kaynaklı olabileceği idi. Araştırmalarım beni “WCF Data Services 5.2 RTM Tools for Visual Studio 2010/2012” ‘ye yönlendirdi. WCF servis ile ilgili bazı hataları gideren bu Tools’u yükledim. Sorunun çözümüne yaklaştığımı ve sonunda olduğunu düşünürken, tekrar aynı hata ile karşılaşmak çok can sıkıcıydı. Bu da sonucu etkilemedi.
  3. Üçüncü düşündüğüm, Entity Framework’ün ürettiği kod ‘dan şüphelenmem sonucunda oldu. Visual Studio 2012 üzerinde eklediğim ADO.NET Entity Data Model nesnesi ile projeye bir sürü yeni dosya eklendiğini fark ettim. Ayrıca üretilen koddaki miras alınan nesne de farklıydı. Neyden farklıydı diye sorduğunuzu tahmin ediyorum, Visual Studio 2010’da eklediğim ADO.NET Entity Data Model nesnesinden farklı birçok dosya ve kod söz konusuydu. Düşündüm ki eğer Visual Studio 2010 ‘daki kod sorunsuz çalışıyor ise, visual studio 2012 ‘de üretilen kod’a karşı WCF servisi gerekli tepkiyi gösteremiyor. Benim yapmam gereken Visual Studio 2012’de Visual Studio 2010’daki gibi ADO.NET Entity Data Model nesnesinin kod üretmesini sağlamak olmalı !! Bu sefer araştırmamı bunun üzerinde gerçekleştirdim. Ulaştığım bir yazıya buradan ulaşabilirsiniz. Ardından çözüme daha da çok yaklaştıran yazıya da buradan ulaşabilirsiniz. Tabii ki yapılacakları kısaca burada açıklayacağım.

Öncelikle sorun;

ADO.NET Entity Data Model nesnesinin kod üretme şeklinde(bu kesinleşti)

  • Visual Studio 2012 ‘de ADO.NET EF Modelinizi çift tıklayarak designer’ı açın.
  • Designer’da boş bir yere tıklama yaptığınızda “Properties” pencerenizde ilgili özellikler gelecektir.

image

  • Properties penceresindeki “Code Generation Strategy” özelliğinin değerini “Default” olarak değiştirin.

image

  • Ardından Solution Explorer’da Model’inize ait “*.tt” uzantılı dosyaları silin.

image

  • Modelinizin bulunduğu projenizi “Rebuild” ile yeniden derleyin.

image

  • Projenizi F5 ile çalıştırdığınızda WCF servisinizin sorun vermeden çalıştığını göreceksiniz.

 

Çözüm basit görünüyor. Sorunun tespitinde baya bir uğraştığımı ve farklı senaryolar düşündüğümden farklı noktalara gittiğimi farketmişsinizdir. Burada kolayca okuduğunuz bu sorun beni 3-4 gündür oyalıyordu. Açıkçası işimi Visual Studio 2010 üzerinden götürdüm fakat sorunu çözmem beni çok sevindirdi. Sizin içinde aynı şekilde hissettireceğiniz düşünüyorum.

 

#amenities

Trakya Üniversitesi Bilgisayar Mühendisliği Yazılım Şenliği

Yoğun bir Yazılım haftası bizleri bekliyor. Fakat ben Ankarada olacağımdan bu fırsatları kaçırmış olacağım. Sanki özellikle bu haftaya hepsi sıkıştırılmaya çalışılıyor gibi.. Anladım anladım bu bana inat yapılıyor Dil çıkaran gülümseme Hiç kaçırmayı istemediğim bir sürü etkinlik bu haftasonu olacak. Dün duyurduğum INETA etkinliğinden sonra bugünde size Trakya Üniversitesinin Yazılım Şenliğini duyurmak istiyorum. Ben katılamayacağım için sorun olmayacak ama katılacak arkadaşlar hangisine gideceği konusunda gerçekten zor bir karar vereceğe benziyor. İki etkinliğinde içeriği çok güzel ve dolu dolu.. Zor bir karar sizleri bekliyor. Ben ise oturup ağlasam mı bilmiyorum Üzgün gülümseme

image