Entity Framework etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Entity Framework etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

19 Mayıs 2012 Cumartesi

Entity Framework - Database First

Merhaba arkadaşlar.
"EntityFramework 4.0 ile gelen ORM araçlarıyla : db yada uygulama model den birini oluştururuz, diğeri ondan oluşur. Varolan bir database i uygulamaya uyarlama işine Database First yaklaşımı, uygulamada var olan nesneleri de database e uyarlama işlemine de Model First yaklaşımı denir."
demiştik ORM giriş yazımızda. Bu yazımda "Database First" yaklaşımını inceleyeceğiz. Database deki her bir tablo bir entity sınıfı, o tablonun her bir kolonu ise bir porperty olacaktır. Entity nin kelime anlamı ise birim yada varlıktır. Primary key ler entity key olacaktır. Bu kolonların tipini ve tablolardaki foreign key olarak tanıladığımız, tablonun diğer tablolar ile arasında olan ilişkiyi nasıl göstereceğimizi göreceğiz. Gelin o zaman Northwind veritabnını map edebilim. Bunun için SqlServer daki diagramımıza bir bakalım.

Projeme Data sekmesi altında, bir ADO.NET Empty Data Model ekliyorum. Adına Nortwind veritabanını modelleyeceğimden dolayı Northwind diyorum.
İki seçenek geldi karşıma. Generate form Database, Empty Model. Ben varolan bir database den türeteceğim, generate edeceğim. Bu nedenle Genarte from Database seçeneğini seçiyorum. Eğer Model First çalışsaydım Empty Model seçeneğini seçecektim. Next dedim.
Aşağıdaki pencerede amaç connection string imizi oluşturmak. Önceden oluşturduysak görüldüğü gibi ismiyle birlikte saklar ve bu seçeneği sunar. Farklı bir connection string ile bağlanacaksam new connection diyerek belirtebilirim. Ben windows authentication ile bağlanacağım. Fakat sql  authentication ile giriş yapacaksam olsaydım sensitive dataları saklama seçenekleri enable oluırdu. Sensitive datalardan kastı user id ve password bilgileridir. Altında app.config dosyasında hangi isimle görüneceğini belirtiyor. Değiştirebiliriz ama kalsın değiştirmiyorum. Bu arada Entity Connection String 'deki EntityClient Provider arka planda SqlClient kullanır. Zaten new connection desem de değiştirilemeyeceğini görebilirsiniz. Bu da ORM 'nin sadece sql server uyumlu olduğunu gösterir. DotNet 4.1 den sonra entity ile oracle a bağlanılabilir. 
Veritabanındaki tablo, view, sp nesnelerim geldi. SqlServer daki tüm nesnelerimin uygulamamda nasıl generate edildiğini görmek açısından tüm nesnelerimi seçiyorum.

Plurize or singularize generated object names seçeneği, sadece ingilizce tablo isimleri için kullanılır. Bu seçeneği tikleyerek, çoğul tablo isimleri entity e dönüştüğünde tekil isimli olacaktır. Bu seçeneği tikliyorum. Her tablo (ara tablo değilse) entitydir. Include forgn key columns in the model seçeneğiyle, tablodaki her bir foregin key için de birer property oluşturacaktır. Bu seçeneği de tikliyorum. Finish diyorum.              

Görüldüğü üzere aşağıdaki gibi Solution Explorer penceresine edmx(Entity Data Model) uzantılı Northwind Data Model 'im geldi. Referanslara da System.Data.Entity, System.Runtime.Serialization, System.Security dll 'lerini kendisi ekledi.
App.config dosyasına da connection stringi belirttiğim isimde yazdı.

  <connectionStrings>
    <add name="NorthwindEntities" connectionString="metadata=res://*/Northwind.csdl|res://*/Northwind.ssdl|res://*/Northwind.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=.;initial catalog=Northwind;integrated security=True;multipleactiveresultsets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />
  </connectionStrings>

Aşağıda edmx dosyasının bir kısmını görüyorsunuz. Görüldüğü üzere her bir tablo entity sınıfı, her bir kolon property olmuş. İşte arkadaşlar Mapping budur. Entity lerin ikonu, class ikonu olan mavi küp şeklinde. Sql server daki tablolara baktığımızda arasında one to many, one to one, many to many ilişkileri mevcuttu. Sql server diagramlarından farklı olarak buradaki ilişkilerde many to many ilişkiler için oluşturulan ara tabloları göremeyiz. Örneğin Customer classının Orders adında bir navigation property si var. Eğer bu iki tabl many to many ilişkili olsaydı, Order tablosunda da Customer değil Customers adında bir navigation property si bulunurdu.
Bir değer bir farklılık ise aşağıdaki gibi one or zero (0,1) to many ilişkisi. one or zero (0,1) to one da olabilirdi. Bu ilişkinin okunmasınsa dikkat edilmesi gereken nokta ya bir müşterinin Order tablosunda birden fazla kaydı bulunabilir. Yada bir müşterini order tablosunda hiç kaydı olmayabilir, şeklinde okunur. Bunun yapılabilmesi için Order tablosundaki CustomerID foreign key kolonu nullable (boş geçilebilir) bir alan olmalıdır. Sql Server a bakalım gerçekten de öyle mi?
Görüldüğü üzere boş geçilebilir bir alan. Modellenirken de bu ilişkiyi 0,1 bir şeklinde belirleniyor.

Bu modellemenin en güzel özelliklerinden biri de yukarıda da göründüğü gibi entitylerin altında bulunan Navigation Properties 'dir. Örneğin Order entity si için bu ilişki şöyle okunur: Her order ın customer i, employee si, details leri, shipper i vardır. Yani bildiğimiz OOP deki Has A kavramı. Bir sınıfta başka bir sınıfın tipinde bir sınıf üyesi bulunabilir. Burada da bir entity de başka bir entity tipinde bir entity üyesi bulunabilir. Order_Details navigation property sinin çoğul olmasının nedeni, bir orderın birden fazla detail inin olabileceğindendir. Entity, navigation property si içinde bulunan entity ile ilişkisine göre, navigation property i tekil yada çoğuldur. Navigation property lerini kullanarak t-sql de inner join ile yapabildiğimiz her şeyi "Order  o = new Order(); o.Customer.CompanyName" diyerek erişebilmemizdir. Örneğin :
Gerçekten büyük kolaylık. Aynı işlemi ado.net ile gerçeklemeye çalışsaydık, inner join li bir sorguyu SqlDataReader nesnesiyle çalıştırmak zorunda kalacaktık. Kısacası navigate prop, bir entity nin aynı model içerisindeki bir başka entity nin özellikleri dir.

Madem bir mapping yani bir modelleme işlemi yapıyoruz, SqlServer daki her bir tipin uygulamada bir karşılığı olmalıdır. Örneğin her bir kolon tipinin nasıl bir karşılıklarının olduğunu görmek için, şimdi de bu property lerin özelliklerine bir bakalım.
 




CustomerName property sinin tipi stringtir. Sql de nchar, nvarchar, char, varchar tipleridir. unicode= true ise nchar yada nvarchar dır, Fixed lengt=true ise nvarchardır. Max length=5 ise nvarchar(5)dir. Bu bilgileri birleştirerek sql server da nvarchar(50) oduğunu, nullable=false ile de boş geçilemez olduğunu anlıyoruz. Bakalım SqlServer da gerçekten de öyle mi?


Bir de OrderID property sine bir bakalım.
Tipi "int32", "StoreGenaratedPattern = identity" yani otomatik artan, "entity key=true" olması sql server da  "primary key" olduğunu gösterir. "Nullable=false" ile de boş geçilemez olduğunu anlıyoruz.

Örneğin "order entity" sindeki "freight property" sinin tipi "decimal" olmuştur. Çünkü sql de "money" olan tiplerin karşılığı "decimaldir". "Precision ve Scale" özellikleri "Decimal(19,4)" olduğunu belirtir.
Görüldüğü üzere her tipin bir karşılığı bulunur.

"Northwind.Designer.cs" dosyası "ORM" mizin nasıl bir "Code Generating" işlemini yaptığını göreceğimiz dosyadır. İncelemek gerekirse:
  • Constructors: Bu region altında "NorthwindEntities" context class ımız hangi yapıcı ile örneklendiğinde, base sınıfı yani "ObjectContext" sınıfı hangi yapıcısıyla örnekleneceği tanımlanmış. DotNet 4.1 de "CodeFirst" yaklaşımını uygularken bu context i, "DbContext" sınıfından türeteceğiz.
  • ObjectSet Properties: Bu region altın "ObjectSet" generic koloksiyonu her enitity tipi için tanımlamış.
  • AddToMethods: ObjectSet Properties 'deki ObjectSet generic koloksiyonlarına ekleme metotları tanımlanmış.
Şimdi de Entities ragion altında ne gibi yapılar meydana geldiğine bir bakalım. 
  • Entities: Bu bölümde ise veritabanındaki her bir tablomun ve view nesnelerinin partial class 'a dönüştürüldüğünü görebiliriz. Yukarıdaki resimde üstteki view, alttaki tablodur. View in de bir tablo gibi generate edilmesinin sebebi geriye tablo gibi bir sonuç döndürmesidir. Partial class olmasının nedeni ise örneğin Shipper classına bir şey eklemek istediğimde, benim yaptığım bu ekleme işlemlerini bu NorthwindEntities classıyla karışmaması açısından fiziksel olarak ayrı, fakat aynı isimde, yine bir partial bir classda tanımlamak isteyebilirim. Bu nedenle partial tanımlanmıştır. Biraz sonra Shipper classı için ToString metotunu override etme ihtiyacı duyacağız. Bunun için aşağıdaki gibi bir "OverrideToStrings" classı oluşturuyorum. İsmini sadece dosya ismi için verdim. Amacım tüm entity lerin "ToString" metotunu bu dosyada ezmek.
    public partial class Shipper    
    {
        public override string ToString()
        {
            return this.CompanyName;
        }
    }

Burada oluşturduğum "Shipper" sınıfının "access modifier" ı, "NorthwindEntities" classındaki "Shipper" class ıyla aynı olmak zorundadır. Aksi halde derleme esnasında bu parital class lar birleştiğinde bir çakışma meydana gelir ve hata ile karşılaşılır. Ama oluşturduğumuz sınıfın "access modifier" ını belirtmezsem hata almam, derleme esnasında diğer partial sınıfın "access modifier" ın alır.

Şimdi Entities region ı altındaki ragion lara da kısaca değinelim.
  • Factory Method: Bu reigon da içinde bulunduğu entity den bir örnek oluşturuluyor.
  • Primitive Properties: Yukarıdaki mapping görüntüsünde entitylerdeki properties sekmesi altındaki propertylere "Primative Properties" denir. "Entities" region altında her entity için "Primitive Properties" region mevcut. Bu region da içinde bulunduğu entity nin propertylerinin (db deki kolonlar) "attiribute" larla özellikleri belirtilmiş. Get ve set metotları oluşturulmuş.
  • Navigation Properties:  Bu ragion da yukarıdaki mapping görüntüsünde entity lerdeki "Navigation properties" leri generate edilmiştir. Primative proplerdan farklı attirbute ler ile nitelenmiştir.
Bir de ObjectContext sınıfındaki bazı metotlara bir bakalım:
Görüldüğü üzere AddObjeect, SaveChanges, DeleteObject, DeleteObject, CreateDatabase, DeleteDatabase verilerimi maüpüle edebileceğim bir çok metotun hazır olarak gelmiş.

Şimdi kodlara geçelim. Aşağıdaki gibi bir arayüz hazırlayalım.
Gerisi bizim bildiğimiz klasik OOP tekniğidir. Insert ve Update işlemlerini aynı "Button" altında tasarlamayı tercih ettim. Siz istediğiniz gibi kullanabilirsiniz. NorthwindEntities nesnesin bize sağladığı metotları ve koleksiyonları kullanarak verilerimizi manipüle edebileceğiz. 

        NorthwindEntities entities = new NorthwindEntities();       //object context
        private void buttonKaydet_Click(object sender, EventArgs e)
        {
            if (selectedShipper == null)
            {
                selectedShipper = new Shipper();
                entities.Shippers.AddObject(selectedShipper);      //remde gerçekleşti.
            }
            selectedShipper.CompanyName = textBoxFirma.Text;
            selectedShipper.Phone = textBoxTel.Text;
            entities.SaveChanges();                     //db e kaydedilir. Db ye modelledi

            Clear();
            listBox1.DataSource = entities.Shippers.ToList();       //databaseden sorgular getirir. ToList siz kullanılırsa contextin remdeki son halini getirir. ToList i eklediğimde db den güncel çeker
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            listBox1.DataSource = entities.Shippers.ToList();            
        }

        public void Clear()
        {
            selectedShipper = null;
            textBoxTel.Text = textBoxFirma.Text = string.Empty;
            textBoxFirma.Focus();
        }

        private Shipper selectedShipper;
        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listBox1.SelectedItem != null)
            {
                selectedShipper = listBox1.SelectedItem as Shipper;
                textBoxFirma.Text = selectedShipper.CompanyName;
                textBoxTel.Text = selectedShipper.Phone;
            }
        }

        private void buttonYeni_Click(object sender, EventArgs e)
        {
            Clear();
        }

        private void buttonSil_Click(object sender, EventArgs e)
        {
            if (selectedShipper != null)
            {
                entities.Shippers.DeleteObject(selectedShipper);
                entities.SaveChanges();
                Clear();
            }
        }
Umarım faydalı olabilmişimdir. Bir başka yazıda görüşmek dileğiyle, hoşçakalın...

Entity Framework - ORM Giriş

Merhaba arkadaşlar.
Artık günümüzde vertabanı kullanmayan uygulama yok dercesine, varsa da kendi yağında kavrulmaya mahkumdur. Bu uygulama bir web, windows yada mobile application olabilir. Yani projemizde bir database modeli, bir de uygulama modelimiz var. Database modelinde tablolar, kolonlar.. Uygulama modelinde ise sınıflar, property ler var.. Database nesnelerin, database modelinden soyutlanarak uygulamada kullanılabilmesi çok zaman alan ve çok zahmetli bir iştir. Aynı şekilde uygulama modelinde kullanılan nesnelerin database modelinde kullanılabilmesi de. İşte arkadaşlar bu nedenle ORM (Object Relation Mapping) araçlarına ihtiyaç duyulmuştur. ORM nin Türkçe karşılığı nesne ilişkili haritalamadır. ORM ile bu iki yapı arasında iki taraflı uyarlama işlemi yapılır. Birbirine dönüşümleri yapılır. Database deki her bir nesne için uygulamada karşılığını, uygulamadaki her bir nesne için de database de karşılığını generate eder. Entity Framework, DotNet 4.0 ile gelen Microsoft 'un ORM aracıdır. Nasıl java için Hibernate varsa(C sharp a uyarlanmış hali NHibernate dir), Microsoft için de Entity Framework vardır. Aslında yaptığı iş tam olarak database modelini uygulamadan soyutlayarak nesneler üzerinden işlem yapmamızı sağlar. Tablo üzerinde select, insert, update, delete metotları otomatik olarak generate ettirilir. Böylece yazılımcıya hız kazandırmış ve hata yapma riskini en aza indirmiştir. Performans bakımından, ADO.NET 'e göre daha yavaş çalışır.

Microsoft, Linq to Sql ile ilk aşamada Sql Server 'ın modellemesini ve ilgili metotları generete ettirmesini sağladı. Ama tam olarak bir ORM aracı değildi, mapping 'de sorunlar vardı. Daha sonra Microsoft Linq to Sql 'e destek vermeyeceğini ve Entity Framework ile orm ye tam bir giriş gerçekleştireceğini açıkladı.  

EntityFramework 4.0 ile gelen ORM araçlarıyla : db yada uygulama model den birini oluştururuz, diğeri ondan oluşur. Varolan bir database i uygulamaya uyarlama işine Database First yaklaşımı, uygulamada var olan nesneleri de database e uyarlama işlemine de Model First yaklaşımı denir. DotNet Framework 4.0 ile şuan sadece SqlClient provider ı sayesinde SqlServer veri tabanları için kullanılmaktadır. Fakat 4.1 ile farklı provider lar sayesinde farklı veritabanlarına da çift taraflı mapping yapmak mümkündür.

Orm in ne olduğunu anladıktan sonra bir de şekle dökmek gerekirse ;


Yukarıdaki şekle bakıldığında database ile uygulama bir orm aracıyla bağlı olduğunu görebiliriz. Bu araç çift taraflı uyarlama işlemi yapıyor demiştik. Veritabanından uygulamamıza bir uyarlama yaptığımızda aradaki bu orm aracı sayesinde bir "code generate" işlemi gerçekleşir. Nasıl bir kod üretiliyor. Database First makalemde daha ayrıntılı işleyeceğim. Bir de Model First yaklaşımı vardı: uygulamadan veritabanına bir uyarlama işlemi yapabiliyordum, bu durumda da veritabanında nasıl tablo oluşturulur bilmeme gerek yoktur. Veya uyarlama yaptıktan sonra uygulamadan veritabanındaki verilerimi manipüle ederken t-sql dili bilmeme gerek yoktur. ORM nin bana sağladığı sınıf metotlarıyla bu işlemleri gerçekleştirebiliyorum. İşte aradaki ORM aracıda bu işlemleri t-sql diline dönüştürüyor.

Orm in ne olduğunu ve nasıl çalıştığını anladıktan sonra maddeler halinde avantajlarına ve dezavantajlarına bakalım arkadaşlar.

Avantajları ;

  • OOP olarak kod geliştirmeye imkan sağlamaktadır.
  • Sql bilmeden bir veri tabanına bağlanabilir ve sql ile ilgili bir çok işlemi rahatlıkla yapabilmek.
  • Herhangi bir database bağımlılığı yoktur. 
  • Oldukça esnek bir yapı sağlamaktadır. Yani oracle kullanıyorken bir anda mssql i kullanabiliriz.
Dezavantajları :
  • Performans. Bir ado.net kadar hızlı çalışmamaktadır.
  • Database den bilgi alış-verişi sırasında kontrol %100 bizde değildir. Bazen oluşturulan sql ifadelerinde sorun çıkabilir veya biz daha güzel ve hızlı çalışacak sql ifadeleri yazabileceğimiz durumlar olabilir.Fakat tüm sql ifadelerini code generating ile kendi oluşturduğu için bu bir dezavantajdır.
  • Veri tabanı bağımsızdır.Fakat uygulama tarafındaki nesneler ile veri tabanındaki nesneler birbirine map edildiği için nesne bağımlılığı vardır.
Entity Framework Database First makalemde görüşmek dileğiyle, hoşçakalın...