C# - Nibernate Mapping (Nesne Haritalama)

Yeni bir projeye başladığımı daha önceki Android yazımda belirtmiştim. Projenin iki ayağından sunucu için olan kısımı .NET web uygulaması olarak yapmaya çalışıyorum. Benim gibi datatable, datarow, sql string kullanmayı alışkanlık haline getirmiş birisi için yeni sayılabilecek MVC ve ORM (Object Relational Mapping) kavramlarını kullanmayı  planladım. Bu bağlamda projeye asp.net MVC3 ile NHibernate kullanarak başladım.

Öncelikli olarak şunu belirtmek isterim ki, kendi adınıza veya küçük ölçekli bir işletme için geliştireceğiniz uygulamalarda bağımlı olduğunuz geliştirici sayısı üç-beş kişiyi geçmiyor, yazacağınız uygulama eklentilerle ve kullanım oranıyla hayal edemeyeceğiniz büyüklüklere ulaşmayacak ise dilediğiniz şekilde kodlayabilirsiniz.

Ama uygulamada geliştirici sayısı artacak, uygulama eklentilerle ve uygulama alanı ile genişleyecekse nesneye dayalı uygulama geliştirme ve onun getirisi olan patternleri ve araçları kullanmak gerekiyor. ORM kavramı da ilk olarak bu kısımda devreye giriyor.

.NET MVC ile uygulama geliştirmeye başlayınca view, controller ile veri katmanını oluşturacak model kavramına giriş yapıyorsunuz. Ben NHibernate kullanmayı tercih ettim. Siz FluentNHibernate, Entity Framework gibi başka ORM araçlarını kullanabilirsiniz.

Bu açıklamalar ne kadar uzarsa uzasın örnek olmadan, kod görmeden kolay anlamayan biri olarak sizi de daha fazla sıkmadan örneğe geçelim. Örnek olarak bir kategori, ürün, sipariş üçlemesinden oluşan veritabanı üzerinden yola çıkalım.


 Veri tabanında tabloları oluşturduktan sonra genel görünüm soldaki şekilde olacaktır.Tabloları oluşturduktan sonra uygulama tarafında tabloları işaret edecek sınıfları proje içerisinde oluşturarak sağdaki resmi elde etmiş olacağız. Uygulama tarafında sınıf şemasını oluşturduktan sonra aşağıdaki gibi bir görüntü elde edeceğiz.
Sınıf şemasını incelediğimizde tüm sınıflarda ortak özellik olarak "ID" üyesini (kolonunu) görmekteyiz. NHibernate ile çalışırken her tabloya ait birincil anahtarı kesin olarak belirlememiz gerekir. Bu uygulamada ise tüm sınıflar için otomatik sayı (int / identity) türünden üyeyi anahtar olarak belirlemiş oldum.

Veri tabanı -> Nesne eşlemesinde veri tabanı üzerinde bulunan her kolonu tablo sınıfı üzerinde bir üyeye denk getirmekteyiz.

Sınıf tarafından bakıldığında veri tabanı kolonundan ve yapısından farklı üyelerin (Örn; Product->Category) de sınıf içerisinde yer aldığını görebiliriz.

Hazırladığımız sınıfları nesne yönelimli programlamaya (OOP) daha uygun hale getirmek için ortak üyeleri bir sınıf altında toplayıp diğer sınıflarda bu ana sınıfı miras almamız gerekir. Bu sayede kod yazımı ve kontrolü daha kolay sağlanmış olur. En azından bundan sonra üreteceğiniz diğer sınıflar için "ID" kolonunu yazmak zorunda kalmazsınız. Sınıfları "_Base" ve "_BaseCaption" adlı iki sınıftan türettikten sonra aşağıdaki şemayı elde etmiş oluruz.


Veri tabanı, tablolar ve sınıfları oluşturduktan sonra asıl konumuz olan eşleşmeyi sağlayacak ilişkileri belirlemeye geldi. NHibernate kullandığınızda bu ilişkileri XML dosyasında oluşturmanız gerekecektir. Aynı şekilde FluentNhibernate kullansaydık .cs uzantılı dosyada kodlama yaparak veri tabanı haritalamasını gerçekleştirmiş olacaktık.

Projenize düzen hakim olması açısından sınıflarınızı ve harita dosyalarınızı ayrı bir klasörde tutmanızı öneririm. Hatta her sınıf için ayrı bir .cs ve .xml dosyası projenin anlaşılması bakımından oldukça faydalı olacaktır. En üst proje resminde haritalar için ayırdığım "Map" klasörü görünmektedir.

Her sınıf için teker teker eşleşme dosyalarını oluşturduk. Dikkat ederseniz dosyaların ismi sınıf isminden sonra ".hbm" takısı alıyor. Uygulama çalıştıktan sonra NHibernate eşleşme dosyalarını bu uzantıyı kullanarak arıyor ve bulduktan sonra eşleşmeyi gerçekleştiriyor.

Burada önemli olan bir konu da bu eşleşme dosyalarının assembly içerisine yerleşmesidir. Her harita dosyasının üzerine sağ tıkladıktan sonra özelliklerden "Build Action" özelliğini "Embedded Resource" yaparak hazırladığımız dosyaların derleme sonucu oluşacak DLL içerisine yerleşmesini sağlayabiliriz.

Harita dosyalarının içerisine gelecek olursak, sizlere iki farklı örnek üzerinde detayları verebilirim. Sipariş ürünleri (OrderProduct) tablosundan gidecek olursak resimde xml içeriği, sınıf şeması, tablosu ve sınıf kodu aşağıdaki şekilde olacaktır.


Görüldüğü gibi xml içerisindeki ikinci satırda NHibernate için haritalama kuralı yazılmaktadır. Burada dikkat edilecek kısım kırmızı çizgi ile belirtilmektedir. Oluşturacağımız namespace ve assembly bu kısımda mutlaka belirtilmelidir.

Tablo ismi ve sınıf ismi belirtildikten sonra "ID" kolonunun belirtilmesi gerekir. Burada birincil anahtar "ID" kolon değerinin otomatik olacağı "<generator class="native"/>" ibaresiyle belirtilmektedir.

Birincil anahtar sonrasında her bir üye tek tek "property" olarak tanımlanır. Üyelerin tanımının peşine gelen satırlarda ilişki tanımı yer alıyor. Tablomuzda bulunmayan fakat sınıfımızda tanımladığımız nesneleri burada ilişkili hale getiriyoruz.

Üyeleri (kolon bazında) tanımladıktan sonra sınıf içerisinde belirlediğimiz ilişkili üyeleri tanımlamamız gerekir. Bu kısımda "many-to-one , one-to-one" ilişkilerini tanımlayabilirsiniz. İlişki tanımlamada "name, class, column" üçlüsü yani yukarı mavi renklerle belirttiğim kısımlara dikkat etmemiz gerekir. Aynı veri tabanı tablolarında olduğu gibi ilişkinin artması performansı çekilecek sorgunun büyüklüğünü etkilediği gibi nesne sınıflarında ilişki tanımının artması da aynı etkileri yapar.

Performans açısından ilk dikkat etmemiz gereken kısım ilişkilerin nesne yaratıldığında yüklenip yüklenmemesini "lazy" özelliği belirlemektir. Üç tip olarak nesne yüklemesini aşağıdaki gibi yapabiliriz.

  • Nesne yüklendiğinde ilişkili tablodaki veri de yüklensin lazy="false"
  • Sadece nesne yüklensin ilişkili tablodaki veri kullanmak istediğim zaman yüklensin lazy="proxy"
  • Sadece nesne yüklensin ilişkiyi gösteren nesne bile yüklenmesin lazy="no-proxy"

Veri tabanında ilişkili tabloların ilişkileri üzerinden birbirlerini etkilmesi "cascade" olayı da haritalamada tanımlanmalıdır. Eğer nesnelerin "insert, update, delete" işlemlerinde ilişkili tabloyu etkilemesini istiyorsanız cascade özelliğine ilgili değeri belirlemeniz gerekir. Oluşturma, silme, güncelleme işleminde ilişkili tablo önemli değilse benim gibi cascade="none" kullanabilirsiniz.


İkinci örneğimizde ilk örnekten farklı olarak "bag" kavramına değinmek isterim. Bir kaydın diğer bir tabloda birden fazla alt kayıt içermesi durumunda liste tipi verileri kullanmamız gerekecektir. NHibernate ile üç liste  tipi kullanabiliriz.

  • "Bag" sırasız liste tipidir. Çift kayıtları (duplicate) içerebilir. .NET karşılığı olarak IList kullanılır.
  • "List" sıralı liste tipidir. Çift kayıtlara (duplicate) izin verilir. İndeks (Index) kolonunun belirtilmesi gerekir..NET karşılığı olarak IList kullanılır.
  • "Set" sırasız liste tipidir. Çift kayıtlara izin verilmez. Her kayıt eşsiz (unique) olmalıdır.
Yukarıdaki örnekte ilişkili alt verileri liste şeklinde elde etmek için "Bag" özelliğini kullandım. Bu özelliği kullanırken anahtar kolonu ve ilişki tipini de belirlemek gerekir. Anahtar (<key/>) kolon, ilişkili tablo üzerindeki kolondur. Ana tablo üzerinde varsayılan olarak id yani ID kolonu ilişkiyi belirler. Biraz karışık olduysa örnek üzerinden açıklayalım.


Ana Tablo
İd
İlişki Tablosu
Anahtar
Product
ID
OrderProduct
ProductID
Order
ID
OrderProduct
OrderID


İlişkiyi belirlemede id kolonunu kullanmak istemiyorsanız, ana tablo üzerinde ilişkiyi belirleyen farklı bir kolon varsa "bag" özelliğinde bunu da belirtebiliriz.

      <!--property-ref ana tablodaki, column ise diger tablo -->
      <key column="OrderID" property-ref="xID"></key>

Bu yazımızda Nhibernate ile kısaca temel tanımlamalara değinmiş olduk. Temel diyorum çünkü  NHibernate kullanmaya başladığınız zaman kullanacağınız parametrelerin bu kısa yazıya sığmayacak kadar çok olduğunu görünce hak vereceksiniz.

Türkiye'nin bölgeleri, illeri ve iller arası mesafeleri...

Uzun zamandır kafamı kurcalayan konulardan birisiydi MVC. Çalıştığım uygulamalarda hiç MVC ile uğraşmamıştım ve görünen o ki (elimde işin eski oluşu nedeniyle) uzun bir süre daha MVC konusuna iş yerinde giremeyecektim.

Bir de aklımda android uygulaması olarak hazırladığım iller yollar projesinden kalma bunu nasıl web ortamına taşırım işi vardı. Doğal olarak tembel bir developer'ın aklında bir çok plan proje vardır. Eskiden büyük düşünceler olsa hayata geçmedikçe projeler küçüldü. Bence iyi oldu aslında. Neyse bunu başka bir başlık altında konuşuruz.

Bu iki düşünce bir araya gelince MVC kullanarak illeryollar için bir web sitesi hazırlamak için kolları sıvadım. Şimdilerde yayına giren sitede aşağıda ismi geçen teknolojileri kullanmaya çalıştım.

  • Asp.NET MVC3 Razor syntax
  • Nhibernate 3.3
  • SQLite veritabanı
Öncelikle şunu söylemeliyim ki MVC gayet anlaşılır ve kolay uygulanabilen bir yapı olmuş. Razor sentaksına ise hemen alışabiliyorsunuz. Gözünüz korkmasın ve kesinlikle bu işlere bir yerden girin. Şu anda iş ilanlarına bakarsanız MVC uygulaması yazma şartı aranır oldu.

"MVC bana ne kattı?" veya "MVC nin bana getirisi ne?" diye soracak olursak öncelikle geliştirme zamanını kısalttı ve kodun anlaşılabilirliğini artırdı. Her zaman bahsedilen katmanlı yapı konsepti kendiliğinden hazır olarak geldiği için hemen adapte olabiliyorsunuz. İkinci olarak artık seo için olmazsa olmaz url rewrite özelliğini framework katmanında atlayıp zıplamadan elde etmiş bulunuyorsunuz. Örnek vermek gerekirse

/iller.aspx?id=61&name=trabzon şeklinde parametrik ifade yerine /iller/detay/trabzon ifadesi hemen gören göz için hem de arama motorları için daha çekici oluyor. Günümüz seo tekniklerinde de bu şekilde kullanılması tavsiye ediliyor. Ha diğer şekilde arama motorları indekslemiyor, tanımıyor mu? Elbetteki tanıyıp indeksliyor ama güncel gelişmeleri de takip etmek gerekir.

illeryollar.com ana sayfa

Velhasıl bu teknolojileri kullanarak illeryollar.com 'u hayata geçirdim. Bundan sonrası ekstra geliştirmeleri nasıl yaparım, için içindeki verileri nasıl zenginleştiririm onu düşünürüm artık.

Bu arada veriler derken veri saklama sqlite veritabanını kullandım. Dosya tabanlı küçücük bir veritabanı da olsa özellikle mobil cihazlarla birlikte popülerliği artmıştır. Veri yoğunluğunun aşırı olmadığı çok fazla bağlantı açılmayacak uygulamalar için özellikle de nhibernate ile etkileişimi kolaylıkla yapılabildiğinden tercih edebilirsiniz.