Archive for the ‘NHibernate’ Category
NHibernate’te Char tipleri ile çalışmak
NHibernate string olarak tanımladığımız özellikleri veri tabanında nvarchar veya varchar2 gibi tiplerde oluşturuyor veya arıyor. ama benim bir projemde denk geldiği şekilde char türündeki bir tablo alanı ile çalışmak gerektiğinde ne yapabiliriz diye bir araştırma yaptığımda açıkçası biraz hayal kırıklığına uğradım. Nesnesel olarak olayı çözemiyoruz gibi. Bunun yerine sql düzeyinde bir çalışma yapmak lazım. Şöyle ki:
1 | public virtual string TelephoneNumber {get; set; } |
şeklinde tanımlanmış alanım için,
1 2 3 4 | Map(x=> x.TelephoneNumber) .Length(4) .CustomSqlType(“CHAR(10)”) .Nullable(); |
şeklinde bir mapping satırı yazmam gerekmekte. allahtan char tipi bütün veri tabanı sistemlerinde aynı kullanıma sahipte herhangi bir problem çıkarmadan çapraz platform çalışabiliyor.
NHibernate Fluent ile tek tablodan birden fazla nesne
Diyelim ki bir sınıftan türemiş birden fazla sınıfınız var. Ve bunları fluent arayüzünü kullanarak NHibernate içinde kullanmak istiyorsunuz. Bunun için öncelikle http://wiki.fluentnhibernate.org/Fluent_mapping adresini ziyaret edip, buradan bilgi edinebilirsiniz. Ancak maalesef yetersiz bir bilgiye sahip olacaksınız. Burada olay çok kısa ve yüzeysel olarak verilmiş. ben konuyu biraz daha ileri götürmek istiyorum. Öncelikle sınıflarımınızı tanımlayalım.
Önce temel sınıfımız. NHibernate bu sınıf için bir tablo üretecek.
1 2 3 4 5 6 7 8 9 10 11 12 13 | public abstract class EKayit { public virtual int KayitID { get; set; } public virtual KayitTipi KayitTipi { get; set; } public virtual string DosyaAdi { get; set; } public virtual byte[] Icerik { get; set; } public virtual string MimeType { get; set; } } |
Şimdide alt sınıflarımızı tanımlayalım.
1 2 3 4 5 | public class ESesKayit : EKayit { } public class EVideoKayit : EKayit { } public class EDigerKayit : EKayit { } |
birde dikkat ettiyseniz alt sınıfın tiplerini tutan bir enum tipimiz var. buda :
1 2 3 4 5 6 | public enum KayitTipi : byte { Ses = 1, Video = 2, Diger = 4 } |
şeklinde tanımlanmış olsun. Şimdi gelelim mapping sınıflarımıza. Önce EKayit ile başlıyoruz :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | public class EKayitMap : ClassMap<EKayit> { public EKayitMap() { Table("TKayit"); Id(x => x.KayitID) .Not.Nullable() .GeneratedBy.Native(); DiscriminateSubClassesOnColumn<byte>("KayitTipi", (byte)KayitTipi.Ses) .CustomType<KayitTipi>() .Not.Nullable(); Map(x => x.DosyaAdi) .Length(100) .Not.Nullable(); Map(x => x.Icerik) .Not.Nullable() .Length(int.MaxValue) .LazyLoad(); Map(x => x.MimeType) .Length(50) .Not.Nullable(); } } |
Dikkat edilmesi gereken en önemli yer DiscriminateSubClassOnColumn tanımı. Burada yanlış tanımlama yaptığınızda şu türde hata mesajları alabiliyorsunuz :
1 2 | [ArgumentException: Requested value 'CD.DataLayer.Entities.EKayit' was not found.] [MappingException: Could not format discriminator value to SQL string of entity CD.DataLayer.Entities.EKayit] |
Bu hataları alınca internette arayışa geçtim. sonunda http://stackoverflow.com/questions/326174/nhibernate-mapping-with-a-class-hierarchy-whose-base-class-is-abstract-and-the-d adresi aradığımı bulmamı sağladı.
Önce problemi anlatayım : Entity sınıfından da gördüğünüz gibi, KayitTipi alanını KayitTipi enum türünden tanımlamışım. Bu özel bir tip olduğu için burada nhibernate’e bu tipin neye karşılık geleceğini bildirmek gerekiyor. bunun için 2 yöntem var esasında. 1. yöntem DiscriminateSubClassOnColumn metodunun jenerik halini kullanmak DiscriminateSubClassOnColumn<byte> şeklinde. böylece sisteme bu elemanın tipini bildiriyorsunuz. 2. yöntem ise DiscriminateSubClassOnColumn metoduna 2. parametreyi atamak. bu parametre yine jenerik metodun tipini belirlediği için esasında 1. yönteme çıkıyor olay. Ben yukarıda bunun ikisini bir arada kullandım.
Şimdi gelelim alt sınıfların mappinglerine.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public class ESesKayitMap : SubclassMap<ESesKayit> { public ESesKayitMap() { DiscriminatorValue((byte)KayitTipi.Ses); } } public class EVideoKayitMap : SubclassMap<EVideoKayit> { public EVideoKayitMap() { DiscriminatorValue((byte)KayitTipi.Video); } } public class EDigerKayitMap : SubclassMap<EDigerKayit> { public EDigerKayitMap() { DiscriminatorValue((byte)KayitTipi.Diger); } } |
Burada önemli olan kısım ise alt sınıfların ClassMap’ sınıfından değilde, SubclassMap sınıfından türetilmeleri. Ayrıca ayırıcı alanda hangi değerin olması gerektiği bu sınıfların yapıcılarında da verilmiş durumda. Tiplerin yine çevirildiğine dikkat edelim.
Böylece işlemi bitirmiş olduk.
