Tags: , , | Categories: asp.net, c#, nhibernate Posted by Admin on 5/6/2011 1:21 AM | Comments (0)

Merhabalar, NHibernate ile geliştirilen uygulamalarda veritabanından bağımsız çalışma yani herhangi bir veritabanına özel tipleri kullanamama durumundan dolayı özel tipler tanımlama gereği duyulmaktadır. Bu örneği daha iyi açıklayabilmek için Enumaration tipli alanların kullanımında yaşanan problem ve problemin çözümü hakkında bahsederek yazıya devam etmeyi uygun görüyorum.

Daha önceki yazılarda bir sınıfın Map edilme işlemine yönelik anlatımları gerçekleştirdim. Tabiki bazı özel durumlardan hemen bahsetmek uygun değildi. İlerledikce istisna durumları incelemek ve anlamak daha da kolaylaşıyor olacaktır.

Herşeyden önce Fluent NHibernate ile herhangi bir veritabanını kullanıldığı düşünülerek çalışılmalıdır. Yazacağımız kodun tamamı nesneye yönelik olması gerektiğinden nesne yönelimli kodlama önemli bir yer tutmaktadır.

Fluent NHibernate ile özel bir kullanıcı tipi tanımlanmak istendiğinde IUserType arayüzünden kalıtılmış bir sınıf ile ilgili tipi tanımlayabiliriz. Örnekten yola çıkacak olursak enumeration olarak tanımlanmış bir property de veritabanı tarafında varchar tipinde tanımlanır ve ilgili enum sabitinin adı olduğu gibi yazılır(KullaniciTipleri.Editor gibi) Bu duruma ait örnek şu şekildedir.

Map tanımlaması:

...
Map(x => x.SubScriberType);
...

 

Enum tanımlaması:

public enum SubscriberTypes : byte
{
    Email = 0,
    Mobile = 1
}


Veritabanı yansıması:


Örnekten de görüldüğü üzere NHibernate SubscriberType alanı için nvarchar(255) uzunluğunda bir veri tipi oluşturmuş. Oysa bu enumeration tinyint türünde bir veritipi ile de ifade edilebilirdi ve doğrusu da budur. Geliştireceğimiz genel bir kullanıcı tanımlı tip ile enum alanlarını Int16 tipinde ifade ederek sorunu büyük ölçüde gidermiş olacağız.

Aşağıda Enum sabitleri için tanımladığım IUserType arayüzünün kullanıldığı sınıfın kaynak kodları yer almaktadır.

using System;
using NHibernate;
using NHibernate.SqlTypes;
using NHibernate.UserTypes;

namespace OMR.Ulak.Entities.Maps.NHibernate.UserTypes
{
    public class EnumTypeMapper : IUserType
    {
        public object Assemble(object cached, object owner)
        {
            return cached;
        }

        public object DeepCopy(object value)
        {
            return value;
        }

        public object Disassemble(object value)
        {
            return value;
        }

        public new bool Equals(object x, object y)
        {
            if (ReferenceEquals(x, y))
                return true;

            if (x == null || y == null)
                return false;

            return x.Equals(y);
        }

        public int GetHashCode(object x)
        {
            return null != x ? x.GetHashCode() : typeof(T).GetHashCode();
        }

        public bool IsMutable
        {
            get { return false; }
        }

        public object NullSafeGet(System.Data.IDataReader rs, string[] names, object owner)
        {
            if (names.Length != 1)
                return null;

            string enmName = NHibernateUtil.Int16.NullSafeGet(rs, names[0]).ToString();

            if (enmName == null)
                return null;

            return Enum.Parse(typeof(T), enmName);
        }

        public void NullSafeSet(System.Data.IDbCommand cmd, object value, int index)
        {
            if (cmd.Parameters == null || cmd.Parameters.Count <= 0)
                return;

            if (value == null)
                cmd.Parameters[index] = DBNull.Value;
            else
                cmd.Parameters[index] = Convert.ToInt16(value);
        }

        public object Replace(object original, object target, object owner)
        {
            return original;
        }

        public Type ReturnedType
        {
            get { return typeof(T); }
        }

        public global::NHibernate.SqlTypes.SqlType[] SqlTypes
        {
            get { return new global::NHibernate.SqlTypes.SqlType[] { SqlTypeFactory.Int16 }; }
        }
    }
}

 

Bu sınıfın kodlama işleminin ardından Map işleminde küçük bir tanımlama daha yapılması gerekiyor o da şöyle:

 

...
Map(x => x.SubscriberType).CustomType<EnumTypeMapper<Enums.SubscriberTypes>>();
...


Veritabanı yansıması ise şu şekildedir:


 

Sorunu bu şekilde bertaraf etmiş oluyoruz. Kullanıcı tipi üzerinde biraz daha geliştirilme yapılırsa daha da sağlıklı sonuçlar alınabileceğini belirterek yazıya son veriyorum. Faydalı olması dileğiyle, mutlu kodlar!

Kahve ısmarlayın

Aşağıdaki kahve simgesine tıklayarak bana paypal üzerinden kahve ısmarlayabilirsiniz. Kahveye olan düşkünlüğü ile bilinen birisi olarak büyük bir zevkle içeceğimden emin olabilirsiniz.


Add comment




biuquote
Loading