2010-07-30 5 views
21

Искал различные списки NHibernate и не получил окончательного ответа. SQL2008 dialect, похоже, не поддерживает тип данных HierarchyID - только новые типы даты и времени.Поддержка HierarchyID SQL 2008 в NHibernate

У кого-нибудь есть хорошая реализация или эффективное обходное решение? Я бы очень хотел использовать HierarchyID в новом приложении. Поддержка этого интересного и мощного типа данных очень не хватает в собственных инструментах MS, поэтому я не шокирован тем, что у NHibernate нет поддержки.

Есть someapproaches там, в котором я еще не углубился. Удивление, если у кого-нибудь есть опыт в том, что работает, что более результативно и т. Д.

Полное раскрытие информации: Я работаю с Castle ActiveRecord, но это похоже на проблему NHibernate.

ответ

9

Отказ от ответственности: Я не эксперт по NHibernate, однако мы используем его с Fluent в предстоящем проекте, который использует SQL Server 2008 R2 и Иерархические идентификаторы. Ниже приведен код, который мы используем в настоящее время в нашей среде разработчиков и не полностью протестирован/уточнен. Я скопировал большую часть кода из другого места (извините, я потерял ссылку!)

Вам необходимо создать определенный пользователем тип, а затем использовать его в своих сопоставлениях. Отображение ниже Fluent, Im не знает, как это сделать, используя ActiveRecord, но я предполагаю, что он должен быть похож!

User Defined Type

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; } 
    } 
} 
} 

Fluent Mapping

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

Читая этот пост:

Castle ActiveRecord: Map to IUserType wihtin Class in C#

ActiveR ecord использует атрибут [Свойство] для сопоставления пользовательских типов. Так что для вас это будет выглядеть примерно так:

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

Надеюсь, это поможет!

+0

Спасибо за ответ Иглы.Этот проект был несколько назад для меня, поэтому я не могу сказать, будет ли это работать (хотя с первого взгляда это выглядит здорово). Если кто-то курант, что он работает, я буду отмечать его как ответ. – JasonCoder

10

Я дал ответ игл на тестовый прогон. Это очень хороший ответ, но есть некоторые изменения, необходимые для его работы (по крайней мере, в .NET 4). Вот что я придумал для своего проекта:

Обновление: Следующий код можно скачать в GitHub и там будет обновлен. 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 
    } 
} 

Картирование

<?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> 

Объект с `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 
    } 
} 
Смежные вопросы