2010-07-30 15 views
21

Ha buscado varias listas NHibernate y no se ha encontrado una respuesta definitiva. El SQL2008 dialect no parece admitir el tipo de datos HierarchyID, solo nuevos tipos de fecha y hora.SQL 2008 Compatibilidad con HierarchyID en NHibernate

¿Alguien tiene una buena implementación o una solución efectiva? Realmente me gustaría aprovechar HierarchyID en una nueva aplicación mía. El soporte para este interesante y poderoso tipo de datos es muy escaso en las herramientas de MS así que no estoy sorprendido de que NHibernate no tenga soporte.

Hay someapproaches que aún no he investigado. Preguntándose si alguien tiene alguna experiencia en lo que funciona, en lo que es más eficiente, etc.

Descripción completa: Estoy trabajando con Castle ActiveRecord pero esto parece un problema NHibernate.

Respuesta

9

Descargo de responsabilidad: No soy un experto en NHibernate, sin embargo, lo estamos utilizando con Fluent en un próximo proyecto que utiliza SQL Server 2008 R2 y las identificaciones de jerarquía. El siguiente código es lo que estamos usando actualmente en nuestro entorno de desarrollo y no está totalmente probado/refinado. Copié la mayoría del código de otra parte (lo siento, perdí el enlace!)

Necesita crear un tipo definido por el usuario y luego usarlo en sus asignaciones. La asignación a continuación es Fluent, no sé cómo hacerlo usando ActiveRecord pero supongo que debería ser similar.

Definido por el usuario 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; } 
    } 
} 
} 

Mapeo Fluido

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

La lectura de este mensaje:

Castle ActiveRecord: Map to IUserType wihtin Class in C#

activer ecord usa un atributo [Propiedad] para mapear tipos definidos por el usuario. Entonces para usted se vería algo como esto:

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

Espero que ayude!

+0

Gracias por la respuesta Needles.Este proyecto fue hace un tiempo para mí, así que no puedo decir si esto funcionará (aunque a primera vista parece sólido). Si alguien responde que funciona, lo marcaré como la respuesta. – JasonCoder

10

Le he dado una respuesta a la respuesta de Needles. Es una muy buena respuesta, pero se necesitan algunos cambios para que funcione (al menos en .NET 4). Esto es lo que se me ocurrió para mi proyecto:

Actualización: El siguiente código se puede descargar en GitHub y se actualizará allí. 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> 

objeto 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 
    } 
} 
Cuestiones relacionadas