1

这是在 hibernate.org 论坛和 nhuusers 列表上发布的,但运气不佳,所以我想我会在这里尝试。

简单地说,假设我有一堂课:

class A
{
   public virtual object SomeValue { get; set; }
}

SomeValue 的类型基本上在 .NET IConvertible 类型集(原语如 bool、byte、char、int16、double、float 等),加上 byte[] 和 string。

我正在尝试为 A 创建一个休眠映射以反映这一点 - 这样我基本上可以将 SomeValue 设置为任意对象(上述类型之一)并稍后检索它。然后,我的 applogic 将对其进行反思以找到类型并做出相应的行为。

到目前为止,我已经尝试创建 IUserType 的实现来尝试处理这个问题。但是我不知道为 SqlType[] SqlTypes 返回什么。我考虑过 new SqlType(DbType.Object) 但是当我尝试从中生成模式时,我得到一个 System.ArgumentException: Dialect does not support DbType.Object

如果我尝试另一种数据类型,那么在尝试转换类型时会出现各种强制转换异常。例如,如果我使用 DbType.Binary,并将 someValue 设置为 int32,则在尝试提交时,我得到 System.InvalidCastException:无法将“System.Int32”类型的对象转换为“System.Byte []”类型。

有没有办法做到这一点?

下面为 IUserType 的非工作实现附加代码(基于http://intellect.dk/post/Implementing-custom-types-in-nHibernate.aspx

public class DataElementType : IUserType

    {
        SqlType baseType = new SqlType(DbType.Binary);
        public SqlType[] SqlTypes
        {
            get
            {
                return new[] { baseType };
            }
        }

        public System.Type ReturnedType
        {
            get { return typeof(object); }
        }

        public new bool Equals(object x, object y)
        {
            if (x == null)
                return false;
            else
                return x.Equals(y);
        }

        public int GetHashCode(object x)
        {
            return x.GetHashCode();
        }

        public object NullSafeGet(IDataReader rs, string[] names, object owner)
        {
            return rs[names[0]];
        }

        public void NullSafeSet(IDbCommand cmd, object value, int index)
        {
            var param = new SQLiteParameter(baseType.DbType, value);
            cmd.Parameters.Insert(index, param);
        }

        public object DeepCopy(object value)
        {
            if (value == null) return null;
            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;
        }
    }
4

1 回答 1

1

事实证明,解决了方言不支持 SqlType(DbType.Object) 的问题,我们通过显式支持 SQLiteDialect 子类化来支持它:

public class SQLiteDialectWithManifestTyping : SQLiteDialect
{
    public SQLiteDialectWithManifestTyping() : base()
    {
        base.RegisterColumnType(DbType.Object, "NONE");
    }
}

要在 Fluent 中使用此方言,请在 SQLiteConfiguration 对象上调用 Dialect()。在 NHibernate 中,适当地设置配置属性 dialect(请参阅参考手册的第 3.5.1 节)。

然后我们可以为我们的映射应用上面的 DataElementType 实现(需要将 SqlTypes 定义更改为:

    public SqlType[] SqlTypes
    {
        get
        {
            return new[] { new SqlType(DbType.Object) };
        }
    }

笔记:

  1. 它并不完美。有一种趋势是将所有离散数字向上转换为 Int64 并浮点数加倍。

  2. 没有隐式的方法来存储大的无符号值(例如 ulong >= long.MaxValue 的值),但这是一个一般的 sqlite 问题(可能是一般的 ado.net 问题?)。

  3. Due to the loss of compile time checking it is probably desireable to put some runtime checks in the NullSafeSet method to ensure the value is a primitive type. Attempting to store general objects seems to just cause the objects ToString() method to be called.

于 2009-11-28T15:27:08.163 回答