Supporto HierarchyID SQL 2008 in NHibernate


21

Ha cercato vari elenchi di NHibernate e non ha trovato una risposta definitiva. Il numero SQL2008 dialect non sembra supportare il tipo di dati HierarchyID, solo i nuovi tipi di data e ora.

Qualcuno ha una buona implementazione o una soluzione efficace? Mi piacerebbe davvero sfruttare HierarchyID in una mia nuova app. Il supporto per questo interessante e potente tipo di dati è gravemente privo di strumenti propri di MS, quindi non sono scioccato dal fatto che NHibernate non abbia supporto.

Ci sono someapproaches là fuori che non ho ancora approfondito. Chiedersi se qualcuno ha qualche esperienza in ciò che funziona, ciò che è più performante, ecc.

Full disclosure: Sto lavorando con Castle ActiveRecord ma questo sembra un problema di NHibernate.

9

Declinazione di responsabilità: non sono un esperto di NHibernate, tuttavia lo stiamo utilizzando con Fluent in un progetto imminente che utilizza SQL Server 2008 R2 e ID gerarchia. Il codice seguente è quello che stiamo utilizzando attualmente nel nostro ambiente di sviluppo e non è completamente testato/perfezionato. Ho copiato la maggior parte del codice da un'altra parte (mi dispiace aver perso il collegamento!)

È necessario creare un tipo definito dall'utente e quindi utilizzarlo nelle mappature. La mappatura che segue è Fluent, non so come farlo usando ActiveRecord ma immagino che dovrebbe essere simile!

definito dall'utente Tipo

namespace YourNamespace { 
    public class SqlHierarchyIdUserType : IUserType { 
    public 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 x.GetHashCode(); 
    } 

    public object NullSafeGet(IDataReader rs, string[] names, object owner) { 
     object prop1 = NHibernateUtil.String.NullSafeGet(rs, names[0]); 

     if(prop1 == null) 
      return null; 

     return SqlHierarchyId.Parse(new SqlString(prop1.ToString())); 
    } 

    public void NullSafeSet(IDbCommand cmd, object value, int index) { 
     if(value == null) { 
      ((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value; 
     } else { 
      if(value is SqlHierarchyId) { 
       SqlHierarchyId hId = (SqlHierarchyId)value; 
       ((IDataParameter)cmd.Parameters[index]).Value = hId.ToString(); 
      } 
     } 
    } 

    public object DeepCopy(object value) { 
     if(value == null) 
      return null; 

     var sourceTarget = (SqlHierarchyId)value; 
     SqlHierarchyId copy = SqlHierarchyId.Parse(sourceTarget.ToString()); 

     return copy; 

    } 

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

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

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

    public SqlType[] SqlTypes { 
     get { return new[] { NHibernateUtil.String.SqlType }; } 
    } 

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

    public bool IsMutable { 
     get { return true; } 
    } 
} 
} 

perfetto Mapping

Map(e => e.YourSqlHierarchyIdProperty) 
    .Column("YourSqlHierarchyIdFieldName") 
    .CustomType<SqlHierarchyIdUserType>(); 

lettura di questo post:

Castle ActiveRecord: Map to IUserType wihtin Class in C#

ActiveR ecord usa un attributo [Proprietà] per mappare i Tipi definiti dall'utente. Quindi per te sarebbe simile a questa:

public class YourDataObject { 
    [Property(ColumnType="YourNamespace.SqlHierarchyIdUserType, YourNamespace") 
    public virtual SqlHierarchyId YourSqlHierarchyIdProperty; 
} 

Spero che ti aiuti!

  0

Grazie per la risposta Needles.Questo progetto è stato un po 'fa per me quindi non posso dire se questo funzionerà (anche se a prima vista sembra valido). Se qualcuno lo rallegra, funzionerà come se fosse la risposta. 01 giu. 122012-06-01 15:43:24


10

Ho dato la risposta di Needles a una corsa di prova. È un'ottima risposta, ma ci sono alcune modifiche necessarie per farlo funzionare (almeno in .NET 4). Ecco cosa mi è venuto in mente per il mio progetto:

Aggiornamento: il seguente codice può essere scaricato da GitHub e verrà aggiornato lì. NHiberntate.HierarchyId.UserType

SqlHierarchyId IUserType

namespace NHibernate.UserTypes 
{ 
    using SqlTypes; 
    using System; 
    using System.Data; 
    using System.Data.SqlTypes; 
    using Microsoft.SqlServer.Types; 

    public class HierarchyId : IUserType 
    { 
     #region Properties 

     public SqlType[] SqlTypes 
     { 
      get { return new[] { NHibernateUtil.String.SqlType }; } 
     } 

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

     public bool IsMutable 
     { 
      get { return true; } 
     } 

     #endregion Properties 

     #region Methods 

     new public 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 x.GetHashCode(); 
     } 

     public object NullSafeGet(IDataReader rs, string[] names, object owner) 
     { 
      object prop1 = NHibernateUtil.String.NullSafeGet(rs, names[0]); 

      if (prop1 == null) return null; 

      return SqlHierarchyId.Parse(new SqlString(prop1.ToString())); 
     } 

     public void NullSafeSet(IDbCommand cmd, object value, int index) 
     { 
      if (value == null) 
       ((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value; 

      else if (value is SqlHierarchyId) 
       ((IDataParameter)cmd.Parameters[index]).Value = ((SqlHierarchyId)value).ToString(); 
     } 

     public object DeepCopy(object value) 
     { 
      if (value == null) return null; 

      return SqlHierarchyId.Parse(((SqlHierarchyId)value).ToString()); 
     } 

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

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

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

     #endregion Methods 
    } 
} 

Mapping

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DataLayer" namespace="NHibernate.Map"> 
    <class name="NHibernate.Map.OrganizationUnit, DataLayer" table="`orgunit`"> 

     <property name="HierarchyId" column="`ou_hid`" type="NHibernate.UserTypes.HierarchyId, DataLayer" /> 
     ... 

    </class> 
</hibernate-mapping> 

Oggetto con hierarchyid

namespace NHibernate.Map 
{ 
    using Microsoft.SqlServer.Types; 

    public class OrganizationUnit 
    { 
     #region Fields 

     private SqlHierarchyId _hierarchyId; 
     ... 

     #endregion Fields 

     #region Properties 

     public virtual SqlHierarchyId HierarchyId 
     { 
      get { return _hierarchyId; } 
      set { _hierarchyId = value; } 
     } 
     ... 

     #endregion Properties 
    } 
}