是否有可能在nhibernate中使用sqlite manifest输入功能?

时间:2009-07-31 17:07:13

标签: nhibernate sqlite nhibernate-mapping system.data.sqlite

这张贴在hibernate.org论坛和nhusers列表上没有太多运气,所以我想我会在这里试试。

简单地说,假设我有一个班级:

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

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

我正在尝试为A创建一个nhibernate映射来反映这一点 - 因此我基本上可以将SomeValue设置为任意对象(上述类型之一)并在以后检索它。然后我的applogic将反思它以找到类型并相应地表现。

到目前为止,我已尝试创建IUserType的实现来尝试处理它。但是我不知道为SqlType [] SqlTypes返回什么。我考虑了新的SqlType(DbType.Object),但是当我尝试从此生成模式时,我得到一个System.ArgumentException:Dialect不支持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;
        }
    }

1 个答案:

答案 0 :(得分:1)

事实证明,解决SqlType(DbType.Object)不受Dialect支持的问题,我们通过明确支持子类化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. 由于缺少编译时间检查,可能需要在NullSafeSet方法中放置一些运行时检查以确保该值是基本类型。尝试存储常规对象似乎只会导致调用对象ToString()方法。