【问题标题】:SQL 2008 HierarchyID support in NHibernateNHibernate 中的 SQL 2008 HierarchyID 支持
【发布时间】:2011-03-23 10:33:38
【问题描述】:

搜索了各种 NHibernate 列表,但没有找到明确的答案。 SQL2008 dialect 似乎不支持 HierarchyID 数据类型 - 仅支持新的日期和时间类型。

有没有人有好的实现或有效的解决方法?我真的很想在我的新应用程序中利用 HierarchyID。 MS 自己的工具严重缺乏对这种有趣且强大的数据类型的支持,所以我对 NHibernate 不支持这一点并不感到震惊。

那里有some approaches 我还没有深入研究。想知道是否有人对什么有效、什么更高效等有一些经验。'

完全披露:我正在使用 Castle ActiveRecord,但这似乎是一个 NHibernate 问题。

【问题讨论】:

    标签: nhibernate sql-server-2008 hierarchyid


    【解决方案1】:

    我已经对 Needles 的答案进行了试运行。这是一个非常好的答案,但需要进行一些更改才能使其发挥作用(至少在 .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
        }
    }
    

    【讨论】:

    • 这在我们的解决方案中效果很好,谢谢!注意:我们不需要 中的 assembly 属性,但是我们在 中替换 DataLayer 的东西是 name 属性是我放在 末尾的东西type
    【解决方案2】:

    免责声明:我不是 NHibernate 专家,但是,我们在即将推出的使用 SQL Server 2008 R2 和 Hierarchy ID 的项目中将它与 Fluent 一起使用。下面的代码是我们目前在我们的开发环境中使用的,没有经过全面测试/完善。我从其他地方复制了大部分代码(对不起,我丢失了链接!)

    您需要创建一个用户定义类型,然后在您的映射中使用它。下面的映射很流畅,我不知道如何使用 ActiveRecord 来做,但我猜应该是相似的!

    用户定义类型

    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 映射

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

    阅读这篇文章:

    Castle ActiveRecord: Map to IUserType wihtin Class in C#

    ActiveRecord 使用 [Property] 属性来映射用户定义类型。所以对你来说,它看起来像这样:

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

    希望对你有帮助!

    【讨论】:

    • 感谢针的回答。这个项目对我来说是不久前的,所以我不能说这是否可行(尽管乍一看它看起来不错)。如果有人说它有效,我会将其标记为答案。
    猜你喜欢
    • 2012-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多