2010-11-19 5 views
0

İkili türden birincil anahtar (16) içeren tabloları içeren eski bir şema var - diğer sütunların bir MD5 karması. NHibernate, Eşitleri uygulamadığı için bir anahtar olarak bayt [] ile çalışmaz, bu yüzden bunu özel bir biçimde paketledim ve NHIbernate'i bir IUserType uygulamasıyla sağladım. MD5Hash bir sınıf değil, bir yapı olduğuna dikkat edin. Ben onun anahtar olarak MD5Hash kullanan bir türe çoktan-bir eşleme yaratana kadarNHibernate: Bir birincil anahtarı birincil anahtar olarak kullanma

public struct MD5Hash : IComparable, IComparable<MD5Hash>, IEquatable<MD5Hash> { 
    private readonly byte[] contents; 
    ... 
} 

Her şey iyi çalıştı.

public class Referenced : IEquatable<Referenced> { 
    ... 
    public virtual MD5Hash Id { get; set; } 
    public virtual string Name { get; set; } // must NOT be null 
    ... 
} 

public class Referencer : IEquatable<Referencer> { 
    ... 
    public virtual MD5Hash Id { get; set; } 
    public virtual Referenced Other { get; set } // may be null 
    ... 
} 

I tipi referencer nesneleri yük girişiminde NHibernate satır bir BOŞ değer içerdiğinde Referans tip ait bir nesne oluşturmak üzere çalışır, böylece anahtar için bir boş değer bkz referencer atamak etmez ve veritabanında Referencer'ı güncelleyin. Başvurulan bir null olmayan sütuna eşlenen bir özelliğe sahip olduğundan, NHibernate bir istisna oluşturur. İstediğim şey, NHibernate'in Other özelliğini null değerine ayarlamasıdır.

MD5Hash'ın tanımını struct yerine bir sınıf olarak değiştirebilirim ancak kodda, MD5Hash'ın hiçbir zaman boş bırakılamayacağını varsayarak, başka bir çözüm aramayacağım bilinmeyen bir yer var.

özel türü için kod ...

internal class MD5HashType : IUserType { 
    public SqlType[] SqlTypes { 
     get { return new[] { new SqlType(DbType.Binary, 16) }; } 
    } 

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

    public new bool Equals(object x, object y) { 
     return Object.Equals(x, y); 
    } 

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

    public object NullSafeGet(IDataReader rs, string[] names, object owner) { 
     var val = NHibernateUtil.Binary.NullSafeGet(rs, names[0]); 
     return (null == val || DBNull.Value == val) ? MD5Hash.Empty : new MD5Hash((byte[])val); 
    } 

    public void NullSafeSet(IDbCommand cmd, object value, int index) { 
     var val = (MD5Hash.Empty == ((MD5Hash)value)) ? null : ((MD5Hash)value).ToByteArray(); 
     NHibernateUtil.Binary.NullSafeSet(cmd, val, index); 
    } 

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

    public bool IsMutable { 
     get { return false; } 
    } 

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

    public object Assemble(object cached, object owner) { 
     return cached; 
    } 

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

MD5Hash IUserType'ın kodu, sorunuzu yanıtlarken çok yardımcı olacaktır. –

+0

Ayrıca, PK olarak bir karma, korkunç bir fikirdir. –

+0

Oyun kodunu ekledim ama yardımcı olduğundan emin değilim. NHibernate koduyla adım attı ve NullSafeGet'in null değerine ve no'lu parametrelere karşı test ettiğini ve "kaydedilmemiş değer" için sağladığım değere karşı test ettiğini anladım. – Faron

cevap

0

sorun NHibernate MD5Hash.Empty hiçbir değeri anlamına geldiğini söyleyemem gibi görünüyor. Bunu işlemek için aşağıdaki gibi özel etkinlik dinleyicileri oluşturmayı denediniz mi? Bir şey gibi: Daha sonra hibernate.cfg.xml yoluyla oturum fabrikasında bu dinleyicileri yapılandırmak zorunda kalacak

public class CustomLoadListener : DefaultLoadEventListener { 
    public override void OnLoad(LoadEvent @event, LoadType loadType) { 
     if(@event.EntityId is MD5Hash) { 
      var id = (MD5Hash) @event.EntityId; 
      if(id == MD5Hash.Empty) { 
       @event.Result = new Referenced { Id = MD5Hash.Empty }; 
       return; 
      } 
     } 
     base.OnLoad(@event, loadType); 
    } 
} 

public class CustomSaveOrUpdateListener : DefaultSaveOrUpdateEventListener { 
    public override void OnSaveOrUpdate(SaveOrUpdateEvent @event) { 
     var entity = @event.Entity as Referenced; 
     if(entity != null && entity.Id == MD5Hash.Empty) { 
      return; 
     } 
     base.OnSaveOrUpdate(@event); 
    } 
} 

: Birisi bunu gerçekleştirmek için nasıl daha iyi bir fikir varsa

<session-factory> 
    <!-- various properties --> 
    <listener type="load" class="NhHacking.CustomLoadListener, NhHacking"/> 
    <listener type="save-update" class="NhHacking.CustomSaveOrUpdateListener, NhHacking"/> 
</session-factory> 

, isterim duymayı seviyorum.

+0

Çok teşekkürler. Bunu deneyeceğim ve bilmeni istiyorum. – Faron