Caner Tosuner

Leave your code better than you found it

Fluent NHibernate Nedir ve Kullanımı

ORM Nedir ?

ORM (object relational mappers) uygulamalarınızda CRUD (Create, Read, Update, and Delete) işlemleri için basit bir şekilde data'ya erişimlerimizi sağlayan yapılardır. Çeşitli ORM framework'leri uzun zamandan beri data-model arasındaki veri alış verişini sağlamak için kullanılmakta ve ORM ler sql scriptleri execute etmeden CRUD işlemlerini doğrudan yapabilmemiz için kod yazmamıza olanak sağlarlar. Özetle, ORM kullanarak uygulamalarımızdaki data-model ilişkisini(database modellemesini) object-model ilişkisine dönüştürebiliriz.

Neden Fluent NHibernate ?

Klasık NHinernate, database de bulunan her bir tablo için class mapping bilgilerini .hbm uzantılı  XML formatındaki dosyalarda saklıyordu ve aslına bakılırsa biraz zahmetli bir işlemdi. Fluent NHibernate'de ise artık .hbm uzantılı mapping bilgilerini içeren XML formatındaki dosyalar kaldırıldı ve bu işlem code-behind'a taşındı ve diğer ORM'lere göre daha hızlı olduğu kabul edilir.

Kısaca özelliklerini sıralamak gerekirse;

  • Easy data-access and data-mapping,
  • Compile-time name- and type-safety,
  • IntelliSense to show you which fluent methods are available at any point,
  • Automapper impl.

Fluent NHibernate ile kolayca Linq sorguları yapabilir ve böylelikle Fluent bir Api oluşturmada kullanabiliriz. Şimdi ise projemize nasıl Fluent NHibernate entegre edip geliştirme yapabiliriz bunu incelicez.

Fluent NHibernate Kurulum

İlk olarak Visual Studio üzerinde yeni bir Console Application projesi açalım. Daha sonra Nuget üzerinden Fluent NHibernate referanslarını projemize indirip kuralım. Install-Package FluentNHibernate

Database Tablo Oluşturulması

Fluent NHibernate kullanabilmek için öncelikle bir database'e ihtiyacımız var. SQL üzerinde FNH_Db adında adında bir database'imiz olsun ve bu db'ye ait aşağıda bulunduğu gibi User adında bir tablo oluşturalım.

CREATE TABLE dbo.Users  
(
    Id int PRIMARY KEY NOT NULL,  
    Name varchar(25) NOT NULL,  
    SurName varchar(25) NOT NULL
)  

User Tablosuna Karşılık Gelen User.cs Oluşturulması

Yukarıda tanımlamış olduğumuz User tablosuna karşılık gelen User.cs aşağıdaki gibi oluşturuyoruz.

public class User
   {
       public virtual int Id { get; set; }
       public virtual string Name { get; set; }
       public virtual string SurName { get; set; }
   }

Mapping Class'ının Oluşturulması

Database tablomuz ve buna karşılık gelen class'ımız hazır ancak halen User objesinde bulunan hangi alan tabloda bulunan hangi alana karşılık geliyor bunu belirtmedik. Bunun için Fluent NHibernate'e ait olan ClassMap adında bir class bulunmakta ve gerekli mapping işlemlerini yapacağımız class ClassMap<T>'den inherit olmuş şekilde oluşturulacak. Burda ki T bizim User class'ımız oluyor.

UserMap.cs adındaki mapping class'ı aşağıdaki gibi olacak şekilde tanımlıyoruz.

   public class UserMap : ClassMap<User>
   {
       public UserMap()
       {
           Id(x => x.Id);
           Map(x => x.Name);
           Map(x => x.SurName);
           Table("User");
       }
   }

DB Connection Sağlanması

Şimdiki işlem ise Fluent Nhibernate kullanarak yukarıda tanımlamış olduğumuz FNH_Db isimli database'e bağlanmak. Bunun için OpenSession adında bir metot oluşturalım.

       public static ISession OpenSession()
       {
           string connectionString = "FNH_Db conn string";
           var sessionFactory = Fluently.Configure()
               .Database(MsSqlConfiguration.MsSql2012
                .ConnectionString(connectionString).ShowSql()
               )
               .Mappings(m =>m.FluentMappings.AddFromAssemblyOf<User>())
               .ExposeConfiguration(cfg => new SchemaExport(cfg)
               .Create(false, false))
               .BuildSessionFactory();
           return sessionFactory.OpenSession();
       }

Tablo'da Bulunan Verileri Alma

Aşağıda yer alan kod bloğu ise db de bulunan tablodaki verileri query etmemizi sağlar.

using (var session = OpenSession())
     {
          var users = session.Query<User>().ToList();
     }

Yukarıda bulunan geliştirmeleri yaptığınızda db bulunan bir proje geliştirmede basitçe connection sağlayarak data-model ilişkisini kurabilirsiniz.  

Not: Yazıyı basit tutmak adına herhangi bir design pattern den bahsetmedim ancak Db olan yerde Crud işlemleri vardır, Crud olan yerde Ado.Net veya ORM vardır, ORM varsa Fluent NHibernate vardır ve Fluent NHibernate de Repository Design Pattern ile birlikte fıstıklı baklava gibi gider :) 

Fluent NHibernate ile ilgili daha detaylı bilgi almak ve geliştirmeleri takip edebilmek için bu linke göz atabilirsiniz.

IComparable Interface'ini Kullanarak Sıralama İşlemi

Primitive type'lar için sıralama işlemini bir şekilde list.Sort() vs gibi metotlar kullanarak yapabiliyoruz. Peki kendi yazdığımız objeler için bunu nasıl yaparız ? .Net tarafında iki objeyi belli field&property'lere göre sıralamamızı veya compare etmemizi sağlayan IComparable<T> interface'i bulunmakta. Bu interface ile List<T> tipidne tanımladığımız değişkenimize bizim belirttiğimiz kritere göre sıralama özelliği kazandırmış oluyoruz. Örnek bir case üzerinden gidelim; Rectangle adında bir objemiz olsun içerisinde Rectangle objeleri bulunan bir array'imiz olsun bu arrayde bulunan objeleri alanı en küçük olandan büyük olana doğru sıralayalım. İlk olarak Rectangle objemizi aşağıdaki gibi tanımlayalım.

    public class Rectangle 
    {
        public double Length { get; set; }
        public double Breadth { get; set; }

        public double Area
        {
            get
            {
                return Length * Breadth;
            }
        }
    }

Şimdi ise üsttede belirtiğimiz gibi dikdörtgen objelerini küçük olandan büyük olana doğru array'de sıralayalım. Bu işlem yapabilmenin bir yolu IComparable interface'ini kullanmak. Rectangle objemizi bu interface'den implement etmek. Implementasyon sonucunda Rectangle class'ı CompareTo adında bir metota sahip olur. Bu metot aracılığıyla compare işlemi yaparak array'imizi sıralayabiliriz. Rectangle class'ımızın implementasyon sonrasındaki görünümü aşağıdaki gibi olacaktır.

    public class Rectangle : IComparable<Rectangle>
    {
        public double Length { get; set; }
        public double Breadth { get; set; }

        public double Area
        {
            get
            {
                return Length * Breadth;
            }
        }

        public int CompareTo(Rectangle other)
        {
            if (this.Area == other.Area)
            {
                return this.Area.CompareTo(other.Area);
            }
            return other.Area.CompareTo(this.Area);
        }
        public override string ToString()
        {
            return this.Area.ToString();
        }
    }

 Şimdi ise sırada yazdığımız bu kodu test etme işlemi var. 

        public static void Main()
        {
            var list = new List<Rectangle>
            {
                new Rectangle() {Length = 7, Breadth = 3},
                new Rectangle() {Length = 5, Breadth = 1},
                new Rectangle() {Length = 9, Breadth = 4},
                new Rectangle() {Length = 2, Breadth = 7},
                new Rectangle() {Length = 3, Breadth = 5}
            };

            list.Sort();//Sort metodu ile array'i belirtmiş olduğumuz kritere göre sıralıyoruz

            foreach (var element in list)
            {
                Console.WriteLine(element);
            }
        }

Projeyi çalıştırdığımızda aşağıdaki gibi bir ekran elde etmiş olacağız.

36
21
15
14
5

 

Servisten Gelmeli || Client Yapmalı

Servisten mi gelmeli yoksa client mı yapmalı ?.. 

Hem server tarafta hem de client tarafta geliştirme yapan biri olarak kolayca söyleyebilirim ki bu iki soru yazılımla uğraşan kişilerin sıkça dile getirdiği sorulardan dır. Özellikle 10-12 kişilik development ekiplerinin bulunduğu projelerde client ve server tarafını geliştiren kişilerin genelde scrum'larda birbirlerine karşı dile getirirler bu cümleleri. Jira'da yeni bir bug açılır analist arkadaş genelde platform belirtilmişse direkt olarak bug'ı o platformu geliştiren kişiye assign eder. Sonrasında o arkadaş ilgili bug'ın altına server-side geliştirmesini yapan arkadaşlardan birini mention'layarak şu sihirli yorumu yazar "servisten gelmeli veya servis yapmalı" veya bunun tam tersi bug server-side geliştirme yapan kişiye açılır o yorum yazarak "client yapmalı" vs şeklinde bir cümle yazar. İşte taht kavgaları tamda o anda başlar.

Aslında bu gereksiz kavganın yaşanmasındaki sebeplerin başında gerekli geliştirme hem client hem de server tarafta da yapılabiliyordur ancak developer geliştirmeyi üzerine almak istemediğinden diğer tarafa atmak ister. Bir kaç ördenk case den yola çıkarak bu soruna çözüm bulabiliriz aslında. 

SOA gerçeklerinden yola çıkacak olursak yönetimin service tarafından yapılabiliyor olması bir projede oldukça önemlidir. Örneğin bir mobil proje geliştiriyorsunuz ve username password yanlış olduğunda kullanıcıya gösterdiğiniz bir uyarı metni var "Girmiş olduğunuz bilgiler hatalıdır." şeklinde. Bu geliştirmeyi client tarafta yaptığınızı düşünelim ve uygulama marketteyken müşteri dedi ki "ya biz şu metni Girmiş olduğunuz bilgiler hatalıdır. Lütfen tekrar deneyiniz." olarak değiştirelim ve bunu hemen 1-2 saat içerisinde yapalım. Proje müdür OK verdi ve geliştirmeyi yapmak için hem ios hem android projelerinde metni değiştirdiniz tekrardan markete submit ettiniz. Uygulamanın market onay sürecinden geçmesi özellikle ios tarafında bazen 1 hafta dahi sürebiliyor. Ne oldu peki müşteri 1-2 saatte halledelim dedi ancak siz 1 haftada halledebildiniz. Eğer client'cı arkadaşların dediği gibi "geliştirmeyi servis yapsın" cümlesini dinleyerek yola çıksaydık ve geliştme service tarafında yapılmış olsaydı hemen ilgili metin değişikliğini db'de bulunan tablodan güncelleyip dakikalar içerisinde isteği yerine getirmiş olacaktık. 

Tabi client'ın her dediği yapıldığında da bir süre sonra servisci arkadaşlarda şu cümleyi ister sitemez duyabiliyoruz "e uygulamayı biz yazıyoz zaten client napıyo ki.." Bu gibi durumlar içinde aslında çok arada kalınan bir case ise ve client'ın yapması daha kolay bir durum ise client'ta yapmak daha doğru olacaktır. Örnek olarak karşılaştığım bir case olmuştu. Uygulamada ürün detay sayfasının bir bölümünün arka planında blur şekilde ürün görselinni gösterilmesi isteniyordu ve ürün resmi dış servis sağlayıcıdan dikdörtgen şeklinde geliyordu. Bunun için client tarafı bu geliştirmeyi servis yapacak demiş ve servis tarafını geliştiren ekibe yani bize şöyle bir geliştirme ticket'ı açıldı "Gelen dikdörtgen resim alınacak resmin en ortada bulunan kısmından 200x200 boyutlarında bulunan kısmı alnıp client'a o şekilde gönderilecek..." ve 2 gün sonra sürüm çıkmayı planlıyoruz.. WTF oluyosun ilk okuduğunda ama geliştirmede bu. Muhakak yapılır ancak ne gerek var o kadar uğraşmaya diyor insan. Daha önceleri client geliştirmesi yapıtığımdan biliyorum ki o resmi client tarafta alıp arka plana yerleştirip ortalamak max 15 dkkalık bir iş olsa gerek. Hemen takım liderine durumu anlattım ve hakiketen client tarafı 15-20 dkka içerisinde istenilen geliştirmeyi yaptı. Burda şunu sorabilirsiniz, e yarın 300x300 olacak şekilde isterlerse ne olacak ? Olabilir tabikide ancak 15 dkka nere 1-2 gün nere. Bu gibi durumlarda ekip olarak çoğunluğa göre karar alınıp en hızlı çözüm hangisi ise o uygulanmaya çalışılır.

Sonuç olarak; serviste mi gelmeli yoksa client mı yapmalı diye tekrar soracak olursak "it depends on the business" diyorum ben yani işe göre değişir ve her ne kadar herşeyi servisten yönetmemiz gereksede gerçek olan o ana göre mantıklı olan çözüm ney ise o taraf yapıyor olmalıdır. Gerçekten iki tarafıda en iyi şekilde bilen bir kişiye danışarak veya iki taraf bir araya gelip istişare yaptıktan sonra en efektif çözüm bulunacaktır.