1 Haziran 2014 Pazar

Entity Framework En Sık Karşılaşılan Hatalar


   Merhaba arkadaşlar,

   Birlikte geçirdiğimiz bu 10 haftalık süreçte sizlere Entity Framework konusu hakkında bilgi vermeye çalıştım. Bu haftaki yazım Entity Framework hakkında paylaşacağım son yazım olacak. Bu süreç içerisinde Entity Framework konusunun yapı taşları olan CRUD işlemlerinden başlayarak, advance topic diyebileceğimiz Inheritance,  Entity Framework Stored Procedure kullanımı gibi bir çok konuyu işledik. Bu haftaki yazımda ise bir önceki haftalarda yaptığımız uygulamalarda karşılaşılma olasılığı yüksek olan hataları bu hataların neden oluştuğunu ve çözümünü anlatmaya çalışacağım.

   System.InvalidOperationException: The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects. 

   Yukarıdaki hata farklı bir içeriğe sahip entity objeleri kullandığımızda ve bu entity objeleri veritabanında bir ilişkiyi özelleştimeye ve veritabanını değişikliğe zorladığında karşımıza çıkar. Bu objeler işlem sırasında birbirlerinin hangi durumda olduklarını bilemezler ve birlikte işlem yapmayı reddederler. Birlikte işlem yapmayı reddettiklerinden ve ikiside aynı veritabanı parçası üzerinde çalışmak istemelerinden ötürü hata oluşur. Birden fazla ObjectContext kullanılan projelerde bu hatayla sıkça karşılaşırız.

    Hatanın en güzel çözümü, birbirleriyle ilişkili entity objeler kullanmaktır. İlgili hatayla karşılaşmamak için size önereceğim yollardan biri foreign key kolonunu ve foreign keye ait idyi bütün entity objelerine bağlamayıp sadece ilişkili olan entity objesine atamak. Böylelikle birden fazla entity objesi aynı veritabanı bölgesinde çalışmayıp sadece ilgili entity objesi orada işlem yapacak ve aynı içeriğe sahip objeler oluşmayacaktır. Bu sizin için bir seçenek değilse, bir başka yolda önceden var olan entity objesi ile aynı içeriğe sahip bir entity objesi eklemek istediğimizde; bu iki objenin içeriğini yenileyip yeni bir objeye bağlayabiliriz yada var olan entity objesini yeni oluşturduğumuz entity objesine atayabiliriz. Fakat bu yollu uygularken dikkatli olmamız gerekir. Çünkü yeni oluşturduğumuz entity objemiz hala eski içeriğe sahip entity objesini refer ediyor ise aynı hatayı almaya devam ederiz.

  System.ObjectDisposedException: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection. 

   Bu hata ise ObjectContex objeleriyle ile Lazy Load entitylerini ilişkilendirmeye çalıştığımızda karşımıza çıkar. Aşağıda bu hata için yazılmış bir test var. Dilerseniz bu test metodunu inceleyelim.

Figür 1-Test Metodu

   Yukarıdaki test metodunda oluşturulan senaryoda geri  product listesi döndüren bir fonksiyonumuz var. Bu oluşturduğumuz liste bir web uygulamasında bulunan listviewin databoundlarını oluşturacak. ProductModel.Name yukarıdaki satırlarda oluşturuluyor. Bu tanımlama birçok deadline(ulaşılamayan satır) oluşmasına neden olacaktır.

   Bu hatayı çözmek için, eğer ObjectContexleri devam ettirmek istiyorsak C# garbage collectionın oluşturduğumuz entitylerin üstüsinden gelmesine izin vereceğiz. Bu işlemi yaptıktan sonra bu hata gerine nullpointer exception almamız beklenir.

   Başlıca hataları yazdıktan sonra Entity Framework konusunda programımızın performansını artırmak için yapılması gereken bir kaç püf noktasından bahsetmek isterim.

   ToList() methodunu Filtrelenmiş Iterationlardan Önce Kullanmayın.

   Bir tablodan ilk 500 entityi getirmek istediğimiz zaman ilk önce ToList() metodunu çağırırsak öncelikle tüm tablodaki entityler gelecektir. Daha sonra ilk 500 entityi getirmek için yazdığımız satır çalışacaktır. Bu durumda ilk 500 entity dışındaki diğer tüm entityler boşu boşuna tablodan getirilmiş olacak ve bu durum bizi performans kaybına neden olacaktır. Kendi bilgisayarımızda bulunan local SQL veritabanında çalışırken bu performans kaybı pek gözlenmez fakat gerçek hayattaki uygulamalarda gözle görülür bir performans kaybı oluşur.

   View State İçerisinde Entity Kullanırken Çok Dikkatli Olun. 

    Mümkün olduğunca View State içerisinde entity kullanmaktan kaçının. İlla kullanmak istiyorsanızda wrapper class oluşturun.

   Çok Gerekli Olmadıkça ObjectContext Oluşturmayın.

   Bu konu daha çok CPU performansıyla alakalı. ObjectContexler CPU performansını büyük oranda etkileyen yapılardır. Mümkün olduğunca az kullanmaya çalışın ya da daha önceden oluşturduğunuz ObjectContexleri tekrar kullanın. Döndüler içerisinde ObjectContex oluşturmayın.

   Entity Framework performans artışı sağlamak için tavsiyelerde bulunduktan sonra Entity Framework blog yazımın sonuna gelmiş bulunuyorum. Umarım birlikte geçirdiğimiz bu 10 haftalık süreç yararlı olmuştur. Entity Framework ile alakalı herhangi bir konuda yardıma ihtiyaç duyarsanız veya herhangi bir sorunuz olursa lütfen yorum bırakın ya da mail yoluyla bana ulaşın. Bir başka blogda görüşmek üzere...

25 Mayıs 2014 Pazar

POCO (Plain Old CLR Objects)


   Merhaba arkadaşlar,

   Bu hafta birlikte POCO objeleri hakkında çalışma yapacağız. POCO objeleri üzerindeki çalışmalarımızı gerçekleştirirken izleyeceğimiz yol şu şekilde olacak;
  • POCO objelerini açıklama
  • POCO objelerini oluşturma
  • POCO objeleri ile CRUD işlemleri
   *POCO Objelerini Açıklama

   Entity Framework, ADO.NET Data Model'da yer alan varlıklarımız(entity) için kendi sınıflarımızı yazabilmemize destek verir. Bu yapıda, varlıklar herhangi bir sınıftan türetilmez, herhangi bir interface'i implemente etmez, veri en sade şekilde tutulur. Böylece projemizi otomatik olarak oluşturulan modelle birlikte gelen birçok koddan kurtarıp, daha basit bir model oluşmasını sağlayabiliriz.

   *POCO Objesi Oluşturma

   Her zaman yaptığımız gibi oluşturduğumuz projeye Entity Framework Data Model oluşturma işlemlerini gerçekleştiriyoruz. Bu haftaki yazımda Microsoft'un hazır veritabanlarından biri olan AdventureWork veritabanını kullanacağım. İlgili veritabanına uygun olarak modelimizi oluştururken table bölümünden sadece ProductCategory tablosunu seçelim ve model oluşturmayı bitirelim. daha sonra .edmx uzantılı pencereye sağ tıklayıp Property penceresinden Code Generation Strategy kısmını None yapalım. Bu işlemi POCO objesi oluşturmak için yapmamız şart. 

Figür 1- Code Generation Strategy

   Code Generation Strategy kısmını None yaptıktan sonra Designer.cs sınıfımızın görüntüsü aşağıdaki gibi olacaktır.

Figür 2-Designer.cs

   Veritabanımız üzerinde yapacağımızı işlemleri gerçekleştirmek için tabloyla aynı isimde olan bir sınıf oluşturmamız gerekiyor. ProductCategory tablosu üzerinde çalışacağımız için ProductCategory isminde bir sınıf oluşturuyoruz ve bu sınıfımıza tablonun attributeleriyle aynı isimde olan propertyleri tanımlıyoruz.

Figür 3-ProductCategory Sınıfı

   Bu işlemi de tamamladıktan sonra Context tanımlaması yapabiliriz. Entity Framework ile otomatik oluşturulan Context, ObjectContext sınıfından kalıtılır. Bunu, bir EF oluşturduğunuzda Designer.cs'ine bakarak da görebilirsiniz.



   İlk önce yukarıdaki using kısmını projemize ekledikten sonra Program:objectContext kısmını kullanabiliriz. Program sınıfımızda, ProductCategory sınıfımızı barındıran ObjectSet tipinden bir özelliğimizin olması gerekiyor. Bunu sağlamak için de, aşağıdaki tanımlamaları  yapıyoruz.

Figür 4-Object Set

   CreateObjectSet() metodu ile yaptığımız örnekleme işlemini Context'imizin Constructor'ında da yapabiliriz. Şu an, sadece tek bir tablo üzerinde çalışıyoruz. O yüzden, bu işlemi Constructor'da yapmak performans ve bellek kullanımı konusunda sorun olmaz ama gerçek hayatta modellerimiz birçok tablodan oluşacak ve bu durumda Constructor'da gereksiz yere yaptığımız örnekleme, çok da optimum bir işlem olmayacaktır. Bu nedenle, en makul yöntem ObjectSet'imizi ihtiyaç duyduğumuzda oluşturmak.

   Bu aşamada, Context'imiz hala hangi bağlantı cümleciğini kullandığını bilmiyor. O nedenle Constructor'da bunu bildirmemiz gerekiyor.

Figür 5- Constructor

   Buradaki ilk parametre entity data modelimizi oluştururken App.Config dosyasına kaydettiğimiz bağlantı cümlesi(ConnectionString)nin adı, ikinci parametre ise Entity Container'ın adı(). Bu adı, Model'e sağ tıklayıp Model Browser dediğimizde açılan pencereden, AdventureWorksModel'ın altındaki EntityContainer'dan öğrenebilirsiniz.

   *POCO CRUD İşlemleri

   POCO objeleri kullanarak CRUD işlemleri yapmak çok basit. İsterseniz Create işleminden başlayabiliriz.

   Kayıt Ekleme

Figür 6-Ekleme

   Dikkat edecek olursak ctx.ProductCategory aslında bizim ObjectSet özelliğimiz. Burada SaveChanges() metodunu çağırmadığımız sürece veritabanı yapılan değişiklikden haberdar olmaz.

   Kayıt Güncelleme

Figür 7-Kayıt Güncelleme

   Context'teki ProductCategory sınıfımızın Model'deki hangi tabloya karşılık geldiğini bulmak için Context sınıfına bir metot yazılabilir ve ya ProductCategory sınıfımızda public const string EntitySetName="ProductCategory" şeklinde tanımlamada yapılabilir. Eğer bir metot yazmak istersek aşağıdaki gibi olmalıdır.
.

   public EntitySetBase GetEntitySet(Object entityType)
{
EntityContainer container = this.MetadataWorkspace.GetEntityContainer(this.DefaultContainerName,DataSpace.CSpace);
EntitySetBase entitySet = container.BaseEntitySets.SingleOrDefault(es => es.ElementType.Name == entityType.GetType().Name);           
return entitySet;
}

   Kayıt Silme

Figür 8-Kayıt Silme

   Öncelikle, sileceğimiz category nesnesini Context'imize ekliyoruz. DeleteObject() metodunu çağırdığımızda aslında silme işlemi gerçekleşmiyor; sadece nesnemiz silinecek olarak işaretleniyor, SaveChanges() dediğimizde siliniyor.

   Kayıt Getirme

Figür 9-Kayıt Listeleme

   Listeleme işlemide yukarıdaki kod blogu gibi yapılabilir. ProductCategory tipinde bir liste oluşturuyoruz. Daha sonra bu listeye bütün ProductCategory değerlerini yazıp listemizi döndürüyoruz. 

   POCO objelerini kullanarak CRUD işlemlerini açıkladıktan sonra bu haftaki yazımın sonuna geliyorum. Faydalı bir yazı olmuştur umarım. Bir sonraki hafta bu zamana kadar yapılan işlemlerin değerlendirmesini yapmak için tekrar burda olacağım. Görüşmek üzere...

11 Mayıs 2014 Pazar

Entity Framework ile Stored Procedure


   Merhaba arkadaşlar,

   Geçen haftaki konumuz olan Entity Framework Kalıtım ile birlikte  Entity Framework'e ait advance konu başlıklarından bahsetmeye başlamıştık. Bu hafta ise hem Entity Framework konuları arasında hemde Sql işlemlerinde önemli rol oynayan Stored Procedure konusundan bahsetmeye çalışacağım.

   Stored Procedure nedir? Hangi zamanlarda kullanılır? İsterseniz ilk önce bu soruları cevaplayarak bu haftaki konumuza başlayalım. Stored Procedure Türkçe karşılığı ile Saklı Yordam veya Saklı Prosedür olarak karşımıza çıkar. Genellikle büyük projelerde kullanılması gereken performans açısından büyük faydaya sahip bir T-Sql ifadesidir. Performans artışını nasıl sağlıyor peki? Stored Procedure veritabanımızda tutulan ve bir kez execute edildikten sonra bir daha execute işlemine gerek kalmadan yani tekrar veritabanı sorgusu yapmaksızın istenilen bilgileri  getirebilen ifadelerdir. Bu cümleden de anlaşılabileceği gibi bir uygulama katmanı değil veritabanı katmanı ifadeleridirler. Stored Procedurler ne zaman kullanılmalıdırlar? Yazımızın başında belirtiğim gibi genellikle büyük çaplı projelerde performans artışını sağlamak amacıyla kullanılırlar. Büyük bir veritabanına sahip bir proje düşünelim. Uygulama katmanında veritabanında aynı Sql sorgusunu birden fazla kullandığımızı varsayalım. Her ne kadar daha önce kullanılmış bir sorgu olsa bile bu Sql sorguları tekrar  kullanmak istediğimizde tekrar veritabanına gidip aynı cevabı döndürecektir. Oysa Stored Procedure veritabanı serverlarında tutulduğu için hem çok hızlı çalışacaktır hemde bir kere kullanıldıktan sonra tekrar veritabanından sorgu yapmaksızın bir sonuç verecektir. Ayrıca Stored Procedurelar parametre alabildikleri için benzer sorgular içinde kullanılabilirler. Buradan da anlaşılabileceği gibi hızın çok önemli olduğu büyük projelerde kullanılması tercih edilir.

   Stored Procedure Entity Framework ile nasıl kullanılır şimdide bundan bahsedelim isterseniz. Veritabanımız geçen haftalarda kullandığımız NorthWind olacak. Entity Framework ile birlikte kullanmak için bir Stored Procedure yazmamız gerekecek. Bunun için MS Sql 2008' i açıyoruz. NorthWind veritabanını import ediyoruz ve Stored Procedure yazmaya başlıyoruz.


   Yukarıdaki Sql Queryi yazıyoruz. Yazıdığımız Stored Procedure parametre olarak bir id alıyor. Daha sonra dışarıdan aldığımız integer tipindeki bu id ile [Products] tablosundaki CategoryID'ye eşit olan ürünlerin ProductID, ProductName attributelerini alıyoruz. Ayrıca Suppliers tablosu ile Join yaparak da Suppliers tablosuna ait olan Country özelliğini kullanıyoruz. Tabi ki bunun içinde Products tablosundan seçtiğimiz ürünlerin SupplierIDleri ile Suppliers tablosundaki Join yaptığımız sağlayıcılara ait SupplierIDleri eşit olması gerekiyor. Bu eşitliği de yaptıktan sonra artık Stored Proceduremiz hazır. Testini yapmak için Stored Proceduremize id olarak 2  atarak çalıştırıyoruz. Çıkan sonuç yukarıdaki gibi olacaktır.

   Stored Procedure yazımını tamamladıktan sonra şimdi Visual Studio kullanarak yapacağımız işlemlere başlayabiliriz. Data model oluşturma işlemininde bu zamana kadar hep Tables kısmını seçerek tamamlıyorduk. Fakat bu sefer Stored Procedure kullanacağımız için Stored Procedure seçeneğini de seçmeyi unutmuyoruz.

Figür 2-VisualStudio Data Model Oluşturma

   Yukarıdaki gibi Stored Procedure seçeneğini seçtikten sonra artık kodlama işlemine başlayabiliriz. İlk önce Sql 2008 de yaptığımız listeleme işlemini Entity Framework kullanarak nasıl yapılacağına bakalım. Listele adında bir method oluşturalım. Stored Procedure oluşturur iken hatırlarsanız integer tipinde bir id alıyordu. Bizim methodunumuzda integer tipinde bir değişken alsın. Methodumuza gönderdiğimiz bu id değişkenine göre bizim methodumuzda bu değişkeni Stored Proceduremize göndersin ve ilgili sonuçlar dönsün.

Figür 3 -Listele Methodu

   Listele methodunu yukarıdaki gibi yazıyoruz. Bu kodda ObjectResult tipinde MevcutUrunler listesi oluşturuyoruz. Bunu yaparken tabi ki daha önceden yazdığımızı Stored Proceduremizi kullanıyoruz. ObjectResult tipinde oluşturduğumuz listenin içine UrunleriGetir Stord Procedure sonucunda dönene tüm ürünleri atıyoruz. Methodumuzu çağırırken id değişkenini 2 olarak atadığımız zaman ekran çıktısı aşağıdaki gibi olması beklenir.

Figür 4-Listele Methodu id=2 Ekran Çıktısı

   Peki listeleme işlemi dışında başla işlemler yapabilir miyiz Stored Procedure üzerinde? Elbette yapabiliriz. Güncelleme silme ve ekleme işlemleri de yapılabilir. Eklemeyi göstermek için bir örnek yapalım. Yine aynı proje üzerinde eğer yeni bir ürünü Stored Proceduremize eklemek istersek aşağıdaki kodlama işlemini yapmamız gerekecektir.

Figür 5 -Ekle Methodu

   Yukarıda görülen ekle methodu asıl olarak bildiğimiz veritabanına ekleme işlemine benzemektedir. Fakat burada farklı olan kısım ise AddObject(proc) kısmıdır. Burada direkt olarak veritabanına ekleme değilde Stored Proceduremize ekleme yapmamızı sağlayan kısım AddObject()'dir.

   Stored Procedure kısmında ekleme ve listeleme işlemini anlattıktan sonra bu haftaki yazımın sonuna geliyorum. Umarım Stored Procedure hakkında ve Entity Frameworkteki kullanımında verdiğim bilgiler faydalı olmuştur. Bir sonraki yazımda görüşmek dileğiyle...

4 Mayıs 2014 Pazar

Entity Framework Kalıtım (Inheritance)


   Merhaba Arkadaşlar,

   Geçen hafta Lazy Loading konusunu işledikten sonra bu hafta daha fazla ilginizi çekeceğini düşündüğüm bir konu olan Entity Framework Kalıtım konusuna değineceğim. Entity Framework Kalıtım konusunu iki temel başlık altında inceleyebiliriz. Bunlardan ilki TPH yani Table-per-Hierarchy diğeri ise TPT yani Table-per-Type' dır.

   Table-per-Hierarchy Inheritance:
   TPH kalıtımı esasen bir tablo üzerinden yapılan kalıtımdır. Daha fazla açıklamak gerekirse veritabanımızda bir tablomuz var. Fakat bu tablo birden fazla Entity model tutuyor. İşte bu şekilde yapılan kalıtım TPH olarak adlandırılır.

   Table-per-Type Inheritance:
   TPT kalıtım ise TPH kalıtımın tam tersi desek pek de yanlış olmaz. Bunda ise veritabanımızda birden fazla one-to-one ilişki içerisinde bulunan tablo var fakat bu tabloların hepside tek bir Entity model şeklinde tutuluyor ise TPT olarak adlandırılır.

   Bu yazımda TPH kalıtımı yolunu nasıl projelerimizde kullanabileceğimizi anlatmaya çalışacağım. Her yazımda olduğu gibi bu yazımda da farklı bir veritabanı oluşturup, oluşturduğumuz bu veritabanını kullanarak işlemleri gerçekleştireceğim. İlk önce veritabanımızı oluşturmak için gerekli Sql Query'i yazalım. Aşağıdaki Query kullanarak sizde kendi veritabanınızı oluşturabilirsiniz.

create database EFInheritance

use EFInheritance

create table Users(
Id int NOT NULL IDENTITY(1,1),
Name varchar(50),
Email varchar(150),
primary key (Id),
)

create table Students(
Id int NOT NULL IDENTITY(1,1),
Major varchar(50),
primary key (Id),
)

create table Employees(
Id int NOT NULL IDENTITY(1,1),
Salary int,
primary key (Id),
)

create table PrintedDocument(
Id int NOT NULL IDENTITY(1,1),
Title varchar(50),
Subject varchar(50),
TypeCode int,
Author varchar(100),
Frequency varchar(50),
primary key(Id),
)

   Veritabanımızı oluşturduktan sonra yeni bir C# Console Application projesi oluşturuyoruz. Oluşturduğumuz projeye hazırladığımız veritabanının modelini ekliyoruz. Modelimizi ekledikten sonra aşağıdaki adımları sırasıyla uyguluyoruz.

   1- User Tablosu ile Student Tablosu Arasında Kalıtım Oluşturma
    User tablosu ile Student tablosu arasında inheritance oluşturmak için User tablosuna Sağ Tık -> Add New -> Inheritance... yi seçiyoruz.

Figür 1-Inheritance Ekleme
  
Karşımıza gelen ekrandan Select a base Entity kısmına User Select a derived kısmına Student seçiyoruz.

Figür 2-User Student Kalıtım

   2- User Tablosu ile Employee Tablosu Arasında Kalıtım Oluşturma
   1. adımda yaptığımız işlemi tekrarlıyoruz. Figür 2' de gösterilen işlemi Employee tablosu için de uyguluyoruz. 
Figür 3- Employee User Kalıtım

   3-Yeni Entity Oluşturup PrintedDocument Tablosuna Bağlama
   Yukarıdaki adımları tamamladıktan sonra PrintedDocument tablosuna bağlamak üzere iki farklı Entity oluşturacağız. Bunun için ilk önce bulunduğumuz sayfaya Sağ Tık -> Add New -> Entity... seçeneğini seçiyoruz.

Figür 4- Entity Ekleme
      Daha sonra karşımıza aşağıdaki gibi bir pencere açılacaktır. Açılan pencerede Entity name kısmına Book Base type kısmını ise PrintedDocument olarak seçip işlemi tamamlıyoruz.

Figür 5- Book Entity Ekleme

   4- Journal Entity Oluşturup PrintedDocument'e Bağlama
   Yukarıdaki basamakta gerçekleştirdiğimiz işlemleri bu adımda da yineliyoruz. Karşımıza çıkan pencereyi aşağıdaki ekran görüntüsü gibi dolduruyoruz.

Figür 6- Journal Entity Oluşturma
   5-Oluşturulan Entitylerin Mapping Tablosunu Düzenleme
   Oluşturduğumuz Entitylerin Mapping Tablosunu düzenlemek için herhangi bir Entity'e Sağ Tık-> Table Mapping seçeneğini seçiyoruz.

Figür 7-Table Mapping

   6- Entitylerin Table Mapping Atamaları
   Sağ Tık-> Table Mapping seçeniğine tıkladıktan sonra Book için şu işlemleri yapmamız gerekecek. İlk olarak Map kısmında PrintedDocumen kısmını çekiyoruz. Daha sonra Condition kısmında ise TypeCode seçtikten sonra karşısına "1" yazıyoruz. 

Figür 8-Book Mapping 

   7-Journal Table Mapping Atamaları
   Yukarıdaki işlemleri Journal Entity içinde tekrarlıyoruz fakat bu sefer Condition kısmına "2" yazıyoruz.

Figür 9 -Journal Mapping
   8-PrintedDocument Property Düzenleme
   Entityleri PrintedDocument tablosuna bağladıktan sonra PrintedDocument'in Abstract propertysini True yapıyoruz.

Figür 10- Abstract True


   9-İşlemleri Onaylama (Validate)
   Yaptığımız tüm bu işlemleri onaylamak için Sağ Tık -> Validate seçeneğine tıklıyoruz.
   
   
Figür 11-Validate

   Data Modellerimizin son görüntüsü aşağıdaki gibi olması beklenir.
Figür 12- Son Görünüm

   Bütün bu işlemleri gerçekleştirdikten sonra artık CRUD işlemlerini gerçekleştirebiliriz.

   Yeni bir öğrenci oluşturmak için aşağıdaki kodu kullanabilirsiniz.

using (var ae= new EFInheritanceEntities()){

   //Create
   var student = new Student(){
       Name = "Hürkan Seyhan",
       Email = "hurkanseyhan@gmail.com",
       Major = "Computer Engineer",
   };
   ae.Users.AddObject(student);

}

   Görüldüğü gibi "Name" ve "Email" attributesini Student tablosunda olmadığı halde onu sanki Student tablosu attributesi gibi kullanabildik ve en sonunda da User tablosunada oluşturduğumuz bu student objesini ekleyebildik.

   Yeni bir employee eklemek istersek;

   //Create
   var employee = new Employee(){
       Name = Ahmet Hamdi",
       Email = "ahamdi@gmail.com",
       Salary = 3500,
   };
   ae.Users.AddObject(employee);

ae.SaveChanger(); // Yapılan değişiklikleri veritabanına bildirmek için.

   Eğer oluşturduğumuz Student'ı silmek istersek;

   var hurkan = ae.Users.ofType<Student>()
                .Single(o=>o.Name="Hurkan Seyhan")
 ae.Users.Delete(Object(hurkan));
 ae.SavaChanges();

   Bu kodda da User tablosu üzerinde bulunan tipi Student olan bir nesneyi nasıl sileceğimizi görmüş olduk.

   Bugünkü yazımı burada sonlandırıyorum. PrinterDocument tablosu ile işlemleri sonraki haftalarda anlatmaya çalışacağım. Umarım faydalı bir yazı olmuştur. 

   Takipte kalmanız dileğiyle...

   Referanslar

27 Nisan 2014 Pazar

Lazy Loading


   Merhaba arkadaşlar,

   Bu hafta birlikte Lazy Loading konusunu öğrenmeye çalışacağız. Lazy Loading kavramının ne olduğunu, Entity Framework konusundaki yerini örneklerle açıklamaya çalışacağım. İlk önce Lazy Loading kavramını açıklayalım. Lazy Loading genel anlamıyla bir nesnenin ihtiyaç duyulmaması halinde çağrılmaması esasına dayanmaktadır. Genel bir örnekle pekiştirirsek bir Web sitesi hayal edelim. Bu web sitesi barındırdığı bütün resimler yüklenmeden açılır. Biz sayfanın ilgili bölümlerini görüntülemeye başladığımızda yine o ilgili bölümde bulunan resimler yüklenmeye başlar. Yani resimleri görüntülemek istediğimiz zaman görüntülenmesi sağlanır. Bu da bize Web sayfasını ilk açmaya çalıştığımızda önemli bir performans katkısı sağlamış olur. Lazy Loading'in temel amacıda budur aslında.

   Lazy Loading'in Entity Framework ile kullanılma amacıda tamamen yukarıda bahsettiğim örnek ile aynıdır. Veritabanımızdaki tabloları nesneler üzerinden kontrol edebildiğimizi daha önceden öğrenmiştik. Oluşturduğumuz nesneleri ihtiyacımız olmadığı zamanlar kullanmazsak bir performans artışı sağlayacağımız şüphesiz. Peki Entity Framework yapısıyla Lazy Loading'i nasıl kullanabiliriz şimdi bunu görelim. Bunun için ilk önce bir veritabanımıza ihtiyacımız var. Örnekleri çeşitlendirmek amacıyla her yazımda farklı bir veritabanı kullanıyorum. Bu yazımda da Northwind veritabanını kullanacağım. Bunun için .bak uzantılı dosyayı buradan indirebilirsiniz. İlgili dosyayı indirdikten sonra .bak uzantılı dosyamızı MS Sql 2008 ile bağlamamız gerekiyor. Bunun için aşağıdaki adımları izlememiz gerekecek.

   Adım 1- İndirdiğimiz dosyayı C:\ klasörüne kopyalayalım.
 
   Adım 2- MS Sql 2008 de Database seçeneğine sağ tıklayıp "Restore Database..." kısmını seçelim.

Figür 1- Restore Database...

   Adım 3- Karşımıza çıkan ekrandan Device kısmını işaretleyip bilgisayarımızda bulunan Northwind veritabanını seçmek için "..." kısmına tıklıyoruz. Bu işlemleri yaptıktan sonra yeni bir pencere açılacaktır. Açılan pencereden Add butonuna basalım.

Figür 2- Veritabanı Ekleme

   Adım 4- Açılan yeni pencereden C:\ klasörüne attığımız Northwind.bak dosyamızı seçip "OK" tuşuna basıyoruz ve veritabanımızı MS Sql 2008'e eklemiş oluyoruz

Figür 3- C:\ Klasöründen Veritabanı Seçme

   Veritabanımızı ekledikten sonra şimdi gelelim örnek kodumuza. Öncelikle C# console application projesi oluşturalım. Oluşturduğumuz projeye her zaman ki gibi DataModel ekliyoruz ve kodlamaya başlıyoruz.

        class Categories
    {
        public int CategoryID { get; set; }
        public string CategoryName { get; set; }
        public string Description { get; set; }
        public string Image { get; set; }   
   }

   Category classımızı oluşturduk ve propertyleri tanımladık. Şimdi Product classımızı oluşturalım.

          class Product
     {
        public int ProductID{ get; set; }
        public string ProductName { get; set; }
       public int CategoryID { get; set; }   
     }

   Kullanacağımız attributeler için propertyleri oluşturduk.

   
         NORTHWINDEntities db = new NORTHWINDEntities();

     List<Categories> categories = db.Categories.OrderBy(c => c.CategoryName).ToList();

       
        foreach (Categories cat in categories)
                {

                    Console.WriteLine(string.Format("{0} [{1}]",
                                               cat.CategoryName,
                                               cat.Products.Count));
                    WriteProducts(cat);

                }
       static void WriteProducts(Categories category)

        {
            foreach (Products prod in category.Products)

            {

                Console.WriteLine(string.Format("\t{0}",prod.ProductName));

            }

        }
  
   Bu kodun ekran çıktısı aşağıdaki gibi olacaktır.
Figür 4- Ekran Çıktısı

   Örneğimizde Category tablosundaki tüm Categoryleri CategoryName attributesine göre sıralayarak bir list oluşturuyoruz. Artık elimizde tüm Categoryler var. Şimdi Products tablosundan da verileri getirip getirmediğini deneyebiliriz. Bunun için "foreach" ile her bir Category altındaki Product elemanlarını almaya çalışalım. Bunun için de "WriteProducts" metodunu oluşturup parametre olarak Categories olarak gönderdik ve bu metodun dönüşünde Category'yi gönderip altındaki Product elemanlarını  Console  yazdırdık.

   Sql Profiler dan arka planda çalıştırılan Sql sorgularını incelediğimizde foreach döngüsüne gelene ve Product elemanları çekilmek istenene kadar sadece tüm kategorileri getiren bir sorgu çalıştığını göreceğiz.

   Ne zamanki ürünler isteniyor o zaman Products koleksiyonu dolduruluyor.

   SELECT
   [Extent1].[CategoryID] AS [CategoryID],
   [Extent1].[CategoryName] AS [CategoryName],
   [Extent1].[Description] AS [Description],
   [Extent1].[Picture] AS [Picture]
   FROM [dbo].[Categories] AS [Extent1]

   ORDER BY [Extent1].[CategoryName] ASC

   Şimdi de kodumuzda Lazy Loading'i kapatalım ve sonuçları gözlemleyelim.

   static void Main(string[] args)
        {

            using (NorthwindEntities db = new NorthwindEntities())

            {
                db.ContextOptions.LazyLoadingEnabled = false; 
                List<Categories> categories = db.Categories.OrderBy(c => c.CategoryName).ToList(); 

                foreach (Categories cat in categories)
                {

                    Console.WriteLine(string.Format("{0} [{1}]",
                                                    cat.CategoryName,
                                                    cat.Products.Count));
                    WriteProducts(cat);

                }

            }
        }

        static void WriteProducts(Categories category)

        {
            foreach (Products prod in category.Products)

            {

                Console.WriteLine(string.Format("\t{0}",prod.ProductName));

            }

        }ORDER BY [Extent1].[CategoryName] ASC

   Entity Modellimizin ContexOptions.LazyLoadingEnabled özelliğini false olarak belirledik. ContexOptions.LazyLoadingEnabled ne için kullanıldığını öğrenmek için Visual Studio'ya sorduğumuzda bize aşağıdaki gibi cevap verecektir.


   Şimdi yapmış olduğumuz örneği açıklayacak olursak; Category elemanlarının altındaki Product propertyleri çağırılacak olursa otomatik olarak yüklenecektir. Ancak Product ile ilgili herhangi bir işlem yapılmadığı zaman veritabanından Product ile ilgili bilgilere erişim yapılmayacaktır.

Figür 5- Ekran Çıktısı-2

   Yukarıda görüldüğü gibi Lazy Loading'i kapattığımız zaman Product bilgilerine erişim olmadı. Lazy Loading'i kapatıp Category başlığı altındaki Tüm Productları listelemek istersek aşağıdaki kodu yazabiliriz.
    
   List<Categories> categories = db.Categories.Include("Products").OrderBy(c => c.CategoryName).ToList();

   Yukarıdaki kod Categoryleri alırken ilgili Productlarıda yüklememizi sağlayacaktır. Sql tarafında da sadece bir sorgu dönecek ve işlemimizi tamamlamış olacağız.

   Fakat Lazy Loading ile bu işlemi yaptığımızda her seferinde bir sorgu dönecek toplam sekiz ayrı Category içinse sekiz farklı sorgu dönecektir. Burada tercih bize kalıyor, eğer tüm kategori ve ürünleri göstermeyeceksek, belirli kategorilerin ürünlerini göstereceksek Lazy Loading kullanmak daha mantıklı.

   Bu haftaki yazımında burada sonuna geliyorum. Haftaya ki yazımda görüşmek üzere...

   Referanslar:

   1- http://www.codeproject.com/Articles/652556/Can-you-explain-Lazy-Loading
   2- http://www.integralwebsolutions.co.za/Blog/EntryId/905/Entity-Framework-5-Lazy-Eager-Explicit-Loading.aspx

20 Nisan 2014 Pazar

LinQ ile Veritabanı İşlemleri

   Merhaba arkadaşlar,

   Geçen hafta LinQ teknolojisini nasıl kullanacağımızı öğrenmiştik. Bu hafta ise LinQ teknolojisi ile birlikte bazı veritabanı işlemlerini gerçekleştirmeye çalışacağız. İlk haftalarda veritabanı işlemleri için ayrı bir veritabanı kullanmıştık. Bu hafta yapacağım programı daha kolay takip etmeniz açısından daha basit ve anlaşılır bir veritabanı kullanacağım.

  İlk olarak veritabanımızı oluşturarak işe başlayalım. MS Sql'de aşağıdaki Queryi execute edelim.

create database School;

use School;

create table Teacher(
Tid int NOT NULL IDENTITY(1,1) ,
name varchar(50),
surname varchar(50),
title varchar(50),
course varchar(50),
primary key(Tid),
)

   Yukarıdaki Query de bir okul veritabanı oluşturduk ve bu veritabanına teacher tablosu ekledik. Teacher tablosuna bazı attributeler ekledikten sonra primary key olan Tid ' yi otomatik artırması için IDENTITY(1,1) kodunu kullandık. Tablomuzu oluşturduktan sonra bu tabloya aşağıdaki şekilde veriler girelim.

Figür 1: Veritabanı Görünüm

   Veritabanımızı oluşturduktan sonra geçmiş haftalarda gösterdiğim şekilde Data Model oluşturuyoruz ve bu haftaki asıl konumuza geçiyoruz.

   Bu hafta LinQ teknolojisini kullanarak veritabanımızdaki verileri özel kurallara göre listelemeyi ve seçili olan veriyi silme işlemlerini öğreneceğiz. Bunun için ilk olarak bir form dizayn edelim ve bu form üzerinden işlemlerimizi yapalım. Formumuzun dizaynı aşağıdaki gibi olsun.

Figür 2: Form Dizayn

   Şekilde de görüldüğü gibi bir DataGridView, bir TextBox, bir Label ve iki Button kullandık ve isimlerini aşağıdaki gibi düzenledik.

DataGridView = dgvTeacher
TextBox = txtTitle
Tamam  Button = btnOnay
Sil Button = btnSil

   Formumuzu dizayn edip gerekli düzenlemeleri yaptıktan sonra şimdi belli bir kurala göre nasıl listeleme işlemi yapacağız onu görelim.

   İlk önce DataModelini oluşturduğumuz School veritabanını kullanmak için aşağıdaki kod blogunu ekleyelim.

   SchoolEntities se = new SchoolEntities();

   Daha sonra Teacher tablosundaki attributeleri kullanmak için GetTeacher classı açıp bütün attributeler için tek tek property oluşturuyoruz.

   class GetTeacher
    {
        public int Tid { get; set; }
        public string name { get; set; }
        public string surname { get; set; }
        public string title { get; set; }
        public string course { get; set; }
    }
}

Listeleme İşlemi:

   Kuralımız öğretmenlerin ünvanları olsun. Textbox'a yazacağımız ünvana göre DataGridView'da ilgili öğretmenler çıksın. Bunun için Tamam Butonun Click metodunu aşağıdaki gibi düzenleyelim.

    private void btnOnay_Click(object sender, EventArgs e)
        {
            List<GetTeacher> lst_Teacher = new List<GetTeacher>();

            lst_Teacher = (from q in se.Teachers
                           where q.title == txtTitle.Text
                           select new GetTeacher
                           {
                               Tid = q.Tid,
                               name = q.name,
                               title = q.title,
                               surname = q.surname,
                               course = q.course,
                           }).ToList();
            dgvTeacher.DataSource = lst_Teacher;

        }

   Geçen hafta anlattığım LinQ konusunda herhangi bir List<> üzerinden nasıl where, select, from gibi komutların kullanılacağını görmüştük. Yukarıda da GetTeacher classı türünde bir List oluşturduk ve bu list üzerinde where komutu ile bir koşul belirtmiş olduk. where q.title == txtTitle.Text   kodu ile TextBox dan aldığımız veriyi q.title'a eşitleyerek istediğimiz ünvanlı öğretmenlerin listelenmesini sağladık.

   ToList() metodu ise GetTeacher türünde oluşturduğumuz lst_Teacher listesine belirtiğimiz koşulu sağlayan öğretmenleri bu listeye atmamızı sağladı.

   Programımızı Yard.Doç ünvana sahip öğretmenleri sıralamak için kullanalım.

Figür 3: Yard.Doç ünvanlı Öğretmenler

Silme İşlemi:

   Silme işlemlerini yapabilmek için kullandığımız DataGridView propertylerinden Multi Select= false, SelectionMode = FullRowSelect yapıyoruz. Bu işlemi yaptıktan sonra getIndex isimli bir değer belirliyoruz.

   public string getIndex;

   Oluşturduğumuz bu string değeri bizim DataGridView'da seçtiğimiz itemin indexini tutacak ve bizde bu index üzerinden silme işlemimizi gerçekleştireceğiz. Seçili iteminin indexini almak için DataGridView metodlarından olan SelectionChanged kullanıyoruz ve aşağıdaki kodlamayı yapıyoruz. 

private void dataGridView1_SelectionChanged(object sender, DataGridViewCellEventArgs e)
        {
            getIndex = "0";
            getIndex = dgvTeacher.CurrentRow.Cells[0].Value.ToString();
        }

   DataGridView üzerinde seçtiğimiz itemın indexini belirledikten sonra artık silme işlemi için gerekli kodlamayı yapabiliriz. Sil buttonunun DialogResult=OK yapalım ve Click metodunu aşağıdaki gibi düzenleyelim.

  private void btnSil_Click(object sender, EventArgs e)
        {
            int index = Convert.ToInt32(getIndex);
            var p = se.Teachers.Where(q => q.Tid == index);
            DialogResult dialog = MessageBox.Show("Silmek İstediğinize Emin misiniz?","Öğretmen Sil", MessageBoxButtons.OKCancel);
           
            if (dialog == DialogResult.OK) 
            {
                p.ToList().ForEach(q => se.Teachers.Remove(q));
                se.SaveChanges();
            }

        }

   Şimdi isterseniz Tid = 5 olan "Cihan Kaleli" öğretmenini silelim.

Figür 4: Silme İşlemi

   OK tuşuna bastığımız zaman ekran görüntüsü aşağıdaki gibi olması beklenir.

Figür 5: Silme İşlemi Sonu

   Bu hafta LinQ teknolojisinden faydalanarak bazı veritabanı işlemleri gerçekleştirdik. Umarım faydalı bir yazı olmuştur. Gelecek hafta görüşmek dileğiyle...

   Referanslar:

11 Nisan 2014 Cuma

LinQ Nedir?


   Merhaba arkadaşlar,

   Geçen hafta beraber Entity Framework kullanarak temel veritabanı işlemleri nasıl yapıldığını incelemiştik. Bu hafta ise geçen haftalarda değindiğimiz konulardan olan LinQ teknolojisinden bahsedeceğim. Öncelikle LinQ'nin geçmişinden bahsetmek istiyorum.

   LinQ (Language Integrated Query) Türkçe karşılığı ile "Dil ile Bütünleştirilmiş Sorgu"dur. .Net Framework 3.5 ve Visual Studio 2008 ile birlikte piyasaya çıkmış,  bir çok alanda kolaylık ve yenilik sağlamıştır. Sağladığı kolaylıkların başında şüphesiz veriye kolay erişim imkanı ve SQL benzeri tek bir söz dizimi ile farklı tiplerdeki verilerin sorgulanmasını sağlamasıdır. Ayrıca C# ile sorgu yazmak, tip güvenli çalışma, ifadelerin otomatik olarak tamamlanması ve IntelliSense gibi özelliklerle geliştiricinin üretkenliğini artırmayı  da sağlar.
   
   LinQ'yi teknolojisine ait sınıflar ve methodları kullanmak istersek System.Linq kütüphanesini kullanmamız gerekir. Bu kütüphanenin tamamını buradan inceleyebiliriz.

   LinQ teknolojisinin bir çok farklı kullanım alanları bulunmakta. Bunlardan bahsedecek olursak;
  • LINQ to Objects: Bellek üzerindeki nesnelerden oluşan koleksiyonları sorgulamak için kullanılır.  
  • LINQ to SQL: SQL Server veritabanlarındaki tabloları sorgulamak için kullanılır. 
  • LINQ to DataSets :ADO.NET DataSet tiplerini sorgulamak için kullanılır.
  • LINQ to XML: Xml verilerini sorgulamak için kullanılır.
  • LINQ to Entity: ADO.NET Entity Framework tarafından oluşturulan varlıkları sorgulamak için kullanılır.
   LinQ geçmişini ve kullanıldığı alanlara göz attıktan sonra bu kavrama biraz daha aşina olduk. Şimdi isterseniz birazda yapısını inceleyelim.

Figür 1: LinQ Yapısı

   Yukarıdaki şekil LinQ yapısının şematik gösterimidir. Dilerseniz bir örnek üzerinden de yapısını ve kullanım şeklini anlatmaya çalışıyım.

   Elimizde bir öğrenci listesi olsun ve bu liste öğrencilerin ismini ve bölümünü içersin;
      
   List<Ogrenci> ogrenciler = new List<Ogrenci>
        {
                      new Ogrenci{ Adi = "Hürkan", Bolum = "Bil. Muh." },
                      new Ogrenci{ Adi = "Orhan", Bolum = "İşletme" },
                      new Ogrenci{ Adi = "Vedat", Bolum = "İstatistik"
                      new Ogrenci{ Adi = "Murtaza", Bolum = "Bil. Muh."  }
       }; 



   Biz bu listeden bölümü Bil. Muh. olan öğrencileri çekmek istediğimizde for , while , swich-case gibi döngüleri kullanabiliriz. Fakat bu döngüler biraz uğraş gerektirdiği  gibi aynı zamanda karmaşıkta olabilirler. Bu gibi durumlarda LinQ imdadımıza yetişiyor.  

   var birOgrenci = (from ogrenci in ogrenciler
                          where ogrenci.Adi == "Hürkan"
                          select ogrenci);

   Yukarıdaki sorguda Hürkan isimli öğrenci tipinde tek bir değişken dönecektir. LinQ teknolojisi sayesinde istersek bir dizi veya bir liste tipinde de değişken döndürmek mümkün. Bunun için bölümü Bil. Muh. olan öğrencileri döndürelim.

   var bilMuhOgrencileri = 
       (from ogrenci in ogrenciler
       where ogrenci.Bolum == "Bil. Muh."select ogrenci).ToList();

   Bu sorguda sonucunda ise bölümü Bil. Muh. olan bir liste elde etmiş olacağız.

   Bu örneğimizi ilk gördüğümüzde sormamız gereken ilk soru bir List <> yapısında "where, select, from" gibi metotların nasıl kullandık? olmalıdır. Bu metotları kullanmamızı sağlayan System.Linq kütüphanesidir. Bu kütüphaneyi projemize import ettiğimiz zaman yukarıdaki linkte bulunan bütün LinQ metotları kullanabiliriz. 

   Şimdi gelelim ikinci sorumuz olan bu var tipi de nedir acaba? ya. Eğer biz var tipinde bir değişken tanımlarsak bunun anlamı ben değişkeni tanımlarken tipini belirtmek istemiyorum demektir. Konuyu örnek vererek açıklamak gerekirse;

   var a= 10//Bu tanımlamada a değerine 10 atanırken tipide int olarak belirlenir.
  
   Bugünkü yazımda LinQ mimarisinin geçmişinden sağladığı kolaylıklardan ve kullanımından bahsetmeye çalıştım. Umarım faydalı bir yazı olmuştur. Bir sonraki yazımda görüşmek üzere...

Referanslar
1- http://msdn.microsoft.com/en-us/library/vstudio/bb397926.aspx
2- http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b
3- http://www.koddunyasi.net/makale_dokuman/sql/linq.pdf