Nesne-İlişkisel Eşleme — EF #S1B1
Geçenlerde bir gün nereden esti bilmiyorum ama Entity Framework’ü baştan sona hızlıca tekrar etme eğiliminde bulundum. Konu hakkında notlarımı paylaşırken dinlediğim müziklerden birini aynı aurayı yakalamak adına bırakıyor ve yazmaya başlıyorum.
Eveeet! Programlama dillerinin ya da geliştirme ortamlarının kendine özgü farklı ORM Framework’leri yani Nesne-İlişkisel Eşleme (Object–Relational Mapping) bulunabilir.
+---------+-------------------+
| C# | Entity Framework |
| JAVA | Hibernate |
| PHP | CakePHP |
| Pyhton | Django |
+---------+-------------------+
Entity Framework, ActiveX Data Object .Net (ADO.NET) uzantısı olup veri tabanı modeli ile çalışmayı mümkün kılar. Her varlık (Entity) modelin bir parçasıdır. Veri tabanını temsil eden model içerisinde (DbContext) tanımlı olan varlık sınıflarından her biriyse veri tabanı tablosunu temsil eder.
Arkadaş Tanıdık Mı? Yetenekleri Neler?
Bağlam(Context) Sınıfı: Yaygın olarak <Veri tabanı Adı> + Context veya <Veritabanı Adı> + Entities şeklinde tanımlanır.
Varlık (Entity) Sınıfı: İçerisinde Scalar (Ölçekleyici) ve Navigation (Gezinme) özellikleri barındırır.
- Scalar (Ölçekleyici), ilkel tür özellikler olarak isimlendirilir ve gerçek verileri depolayan veri tabanı tablosundaki bir sütuna eşittir.
- Navigation (Gezinme), farklı bir varlıkla ilişkiyi temsil eder. Tabii ki ilişkisel veri tabanlarında tablolar arasında ilişkiler kurabilmek için Primary Key ve Foreing Key dediğimiz anahtarlara sahip olmamız gerekir. Bunun haricinde Referans ve Koleksiyon gezinme olarak 2 tür gezinme özelliğimiz bulunur. Referans Gezinme (1–1 ve 1-n) iken Koleksiyon Gezinme (n-n) ilişkileri tanımlar.
Entity Framework Özellikleri
Bağlam (DbContext), yalnızca veri tabanından alınır alınmaz tüm varlık nesnelerinin referansı tutmakla kalmaz, aynı zamanda varlık durumlarının kaydını tutup, özelliklerinde yapılan değişiklikleri de takip eder. Bu nedenle, varlık durumları entity framework’te önemli bir rol oynar.
Varlıkları (entities) ilgilendiren 5 farklı durum vardır. (Added, Deleted, Modified, Unchanged, Detached). EntityState, varlıklarımızın o anki durumunu bize bildirir. Context.Entry(entityObject).State
yöntemi ile ilgili varlığın durumu çekilebilir/değiştirilebiliriz.
- Unchanged (Değişmemiş): Bağlam (context) örneği üzerinden alınan varlıklarda bir değişiklik yapılmadığı durumdur.
- Detached (Tarafsız, Bağımsız): Varlık (entity) herhangi bir bağlam tarafından izlenmemektedir. Yani varlık (entity) ile bağlam (dbcontext) arasında aktif bir bağ yoktur.
EF 6.4 Database-First
Veri tabanı öncelikli yaklaşım adından da anlaşılacağı üzere, varlık modeli oluşturmak için önceliği veri tabanına verdiğimiz model oluşturma prensibidir. Bu yaklaşımda, veri tabanında var olan tablolar üzerinde çalışır ve genel veri tabanı ayarlamalarımızı/düzenlemelerimizi veri tabanı yönetim araçları (örneğin, SQL Server) üzerinden yaparız.
Entity Data Model (EDM)
- Veri tabanı öncelikli yaklaşımı için EF Designer from database
- Model önceliklik yaklaşımı için Empty EF Designer model
- Kod öncelikli yaklaşım için Empty Code First Model ve Code First from database seçenekleri mevcuttur.
Bağlam (Context) Sınıfı
DbContext, Entity Framework’de önemli bir sınıftır. Etki alanınız veya varlık sınıflarınız ile veri tabanı arasında bir köprüdür.
Aşağıdaki faaliyetlerden sorumludur.
- Sorgulama: LINQ-to-Entities sorgularını SQL sorgusuna dönüştürür ve veri tabanına gönderir.
- Değişiklik İzleme: Veri tabanından sorgulandıktan sonra varlıklarda meydana gelen değişiklikleri izler.
- Kalıcı Veri: Veri tabanına ekle, güncelleştir ve sil işlemlerini varlık durumlarını referans alarak gerçekleştirir.
- Önbelleğe Alma: Varsayılan olarak ilk düzey önbelleğe alma sağlar. Bir bağlam sınıfının ömrü boyunca varlıkları depolar.
- İlişki Yönetimi: Db-First veya Model-First yaklaşımında CSDL, MSL ve SSDL kullanarak ve Code-First yaklaşımında akıcı API yapılandırmalarını kullanarak ilişkileri yönetir.
- Nesne Maddeleştirme: Veri tabanındaki ham verileri varlık nesnelerine dönüştürür.
Bağlam Sınıfı Yöntemleri
- SaveChanges()
- SaveChangesAsync()
- OnModelCreating(): Veri tabanı ilk defa oluştururken tetiklenen bir sanal (virtual) metottur. Code-First yapısında DbContext’ten miras alarak oluşturulan bağlam sınıfında override ederek kullanılabilir. Bu yöntem sayesinde veri tabanı tabloları oluşturulmadan araya girecek tablo isimlerine müdahale edebilir veya kolonlara istenilen ayarlar gerçekleştirilebilir. OnModelCreating yöntemi, modeli Entity Framework’te DbModelBuilder Fluent API kullanarak yapılandırmamıza olanak tanır.
- Entry(): Entity’in durum bilgilerine erişmek ve müdahalede bulunmak için kullanılır.
Bağlam Sınıfı Özellikleri
- ChangeTracker: Bağlam örneğinin izlediği varlık örnekleri için bilgilere ve işlemlere erişim sağlar.
- Configuration: Yapılandırma seçeneklerine erişim sağlar.
- Database: Veri tabanıyla ilgili bilgilere ve işlemlere erişim sağlar.
EF 6.4 CODE-FIRST
Kod öncelikli yaklaşımda, önce varlık ve bağlam sınıflarınızı yazmaya başlarsınız. Ardından geçiş komutlarını kullanarak bu sınıflardan veri tabanını oluşturursunuz. Database-First yaklaşımının aksine Code-First’de görsel bir tasarım aracı ile ya da veri tabanı tablosundan varlık sınıfı üretmeyiz.
Birincil Anahtar Belirleme
Veri tabanında oluşturacağımız tablolarda Primary Key çok önemlidir. Entity Framework, oluşturduğunuz varlık sınıflarında yer alan özelliklerden herhangi biri ön koşula uyuyorsa bu özellliği otomatik olarak Birincil Anahtar sütunu olarak aktarır.
- Örneğin özelliğin adı Id olmalı ya da <Varlık Adı> + Id şeklinde olmalıdır. [ProductId]. Bu kuralda büyük küçük harf duyarlı değildir.
Varlık sınıfı içerisinde bu kurala uygun oluşturduğunuz bir özellik mevcut ise Entity Framework, sınıftan tablo oluştururken bu özelliği birincil anahtar sütun olarak aktaracaktır. Sadece kurala uyan ilk özelliğin birincil anahtar olacağı unutulmamalıdır.
Öznitelikler (Attribute) İle Yapılandırma
- NotMapped: Entity framework, varsayılan olarak varlık içerisinde her bir özellik için bir sütun oluşturacaktır. Fakat bazı durumlarda girilen herhangi bir özelliğin veri tabanı tablosunda sütun olarak oluşturmasını istemeyebiliriz. Bu gibi durumlarda [NotMapped] attribute ile belirtilen özellik hariç tutulabilir.
- TimeStamp: Veri tabanında satır sürümü (RowVersion) olarak kullanılmak istenen sütunun veri türünü belirtmek için bir özelliğe kullanılır.
- ConcurrencyCheck: İlgili sütunun iyimser eş zamanlılık denetimine dahil edilmesi gerektiğini belirtmek için bir özelliğe uygulanabilir.
VERİ TABANI OLUŞTURMA
DATABASE.CREATEIFNOEXISTS()
Create() yöntemi, Code-First yaklaşımı ile oluşturduğunuz bir uygulamanın ilk çalıştırılmasında kullanılabilen pratik bir yöntemdir. Fakat bu yöntem veri tabanı ilk kez oluşturulduktan sonra çalıştırılır ise hata verecektir. Sürekli olarak veri tabanı sunucusunda veri tabanının olup olmadığını kontrol pek uygun bir yöntem değildir. Geliştirilen uygulamanın daha konforlu çalışabilmesi için Create() yöntemi yerine CreateIfNoExists() yöntemi kullanılabilir. Bu yöntem istenilen veri tabanı, veri tabanı sunucunda yok ise yeni veri tabanı oluşturma işlemi gerçekleştirir.
SETINITIALIZER()
SetInitializer(), Varlık veri modellerinizden bir veri tabanı yaratma işlemini gerçekleştiren yöntemdir. “Başlatıcı” olarak adlandırılır. Bu yönteme verilen parametreler ile veri tabanı sunucusu üzerinde veri tabanı ve tablolarınızı oluşturabilirsiniz. Üç çeşit uygulama türü, yani üç tür başlatıcı vardır.
- CreateDatabaseIfNoExists
- DropCreateDatabaseAlways
- DropCreateDatabaseIfModelChanges
Lambda İfadeleri
Lambda ifadeleri, delege, anonim yöntem, fonksiyon ve expression tree tiplerini pratik bir şekilde tanımlamamıza yarayan ve .NET 3.0 ile hayatımıza girmiş bir özelliktir. Tüm lambda ifadeleri lambda operatörünü (=>) kullanır. Lambda operatörünün sol tarafı varsa giriş parametrelerini (argümanlarını), sağ tarafı ise kod bloklarını ya da koşullarını barındırır. Lambda operatörünün sağ tarafında herhangi bir koşul tanımlandığı ya da herhangi bir yöntem çağrımının yapıldığı kullanım şekillerine Expression Lambda denmektedir.
products.Where(product => product.Name == "LTunes Tribe");
Find (Primary Key)
First, FirstOrDefault, Single, SingleOrDefault metotlarının alternatifi değildir! Bu çok yaygın olarak karıştırılan ve benim de kırmızı çizgim haline gelmiş bir konudur. Find, nesnenin (tablonun) birincil anahtar sütunları üzerinde hızlı arama ve sonuç alma işlemini yapabileceğimiz bir metottur.
Tribe tribe = _context.Tribes.Find(1);
Find() yöntemini kullanırken parantez içerisine girdiğimiz değerin yalnızca birincil anahtar (PrimaryKey) sütunu üzerinde arama yapar.
Any() ve All()
Bazen veri tabanı üzerinde sorgulama yaparken, verileri elde etmek değil, sadece o verinin var olup olmadığını ya da kayıtlarımızın tümünün verdiğimiz koşula uyup uymadığı bilgisini almak isteriz. Any() ve All() bu amaçlar için kullanılan iki yöntemdir.
Any(), verilen koşula uygun bir kayıt var ise geriye “true” değerini yok ise “false” değerini döndürür.
_context.Vehicles.Any(vehicle => vehicle.BrandName == "Seat");
All(), veri tabanı tablosundaki tüm kayıtların verilen koşula uyup uymadığını sorgular. Tüm kayıtlar koşula uyuyorsa “true” değerini, tek bir kayıt bile koşul dışındaysa geriye “false” değerini döndürür.
_context.Vehicle.All(vehicle => vehicle.ColorId == 1);
Bağlantısız Senaryo (DbContext)
Bağlantısız ya da bağlantısı koparılmış bir varlıktan kasıt, DbContext’ten türetilen bağlam örneğinin kapsam dışında oluşturulan varlıklardır. Doğal olarak bu varlıklar, bağlam örneği tarafından izlenemez. Bu varlıkların EF tarafından veri tabanı üzerinde işleme alınabilmesi için varlık için uygun EntityState
değerini bildirmemiz gerekir. Entity Framework veri tabanı üzerinde Update, Delete ve Insert komutlarını bağlam örneğindeki EntityState değerine göre oluşturur. Bağlam örneği varlığın bir EntityState değeri mevcut değilse, bu varlık EF tarafından görülmez.
Bağımsız oluşturulmuş/örneklenmiş bir varlığı, bu yöntem ile izleyebilir ve EntityState değerine müdahale edebiliriz.
- Ekleme
context.Entry(entity).State = EntityState.Added;
- Güncelleme
context.Entry(entity).State = EntityState.Modified;
- Silme
context.Entry(entity).State = EntityState.Deleted;
Attach()
Bağımsız olarak oluşturulan/örneklenen varlığı bir bağlam örneğine ilişkilendirmeyi sağlayan yöntemdir. Attach() metodunun çağrılışının ardından ilgili varlık artık ilişkilendirildiği bağlam örneği üzerinden izlenebilir fakat Add() yönteminden farklı olarak EntityState değeri Unchanged (değişmedi) olarak kalır. Bu yöntem ile bağlam örneğine bir varlık ilişkilendirdiğinizde, ilgili varlık üzerinde hiçbir işlem yapılmadan çağırılan SaveChanges() yöntemi bu varlığı veri tabanına eklemez.
#S1B2 bölümünde görüşmek üzere. Tot ziens 😎