是否可以在nhibernate中使用sqlite清单键入功能? [英] is it possible to use sqlite manifest typing features in nhibernate?

查看:74
本文介绍了是否可以在nhibernate中使用sqlite清单键入功能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

SomeValue的类型基本上位于.NET IConvertible类型(原始类型,如bool,byte,char,int16,double,float等)的集合中,再加上byte []和字符串.

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

到目前为止,我已经尝试过创建IUserType的实现来尝试解决此问题.但是我不知道要为SqlType [] SqlTypes返回什么.我考虑了新的SqlType(DbType.Object),但是当我尝试从中生成模式时,我得到了System.ArgumentException:方言不支持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;
        }
    }

解决方案

事实证明,方言不支持SqlType(DbType.Object)的问题,我们通过使用显式支持将SQLiteDialect子类化来使其受到支持:

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

要在Fluent中使用此方言,请在SQLiteConfiguration对象上调用Dialect().在NHibernate中,适当地设置配置属性方言(请参阅参考手册的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()方法.

this was posted on hibernate.org forums and nhusers list without much luck, so I thought I would try here.

Put simply, suppose I have a class:

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

the type of SomeValue is basically in the set of .NET IConvertible types (primitives like bool, byte, char, int16, double, float etc.), plus byte[] and string.

I am trying to create a nhibernate mapping for A to reflect this - so that I can basically set SomeValue to an arbitrary object (of one of the types above) and retrieve it later on on. My applogic will then reflect on it to find the type and behave accordingly.

So far I have tried Creating an implementation of IUserType to try and handle this. However I don't know what to return for the SqlType[] SqlTypes. I considered new SqlType(DbType.Object) but when I try to generate a schema from this I get a System.ArgumentException: Dialect does not support DbType.Object

If I try another data type then I get various cast exceptions when trying to convert the type. For instance if i use a DbType.Binary, and set someValue to an int32, upon attempting to commit I get System.InvalidCastException: Unable to cast object of type 'System.Int32' to type 'System.Byte[]'.

Is there a way to achieve this?

Attached code below for a non-working implementation of IUserType (based on 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;
        }
    }

解决方案

It turns out to get around the problem with SqlType(DbType.Object) being unsupported by the Dialect, we make it supported by subclassing the SQLiteDialect with explicit support:

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

To use this dialect in Fluent, call Dialect() on your SQLiteConfiguration object. In NHibernate, set the configuration property dialect appropriatelly (see section 3.5.1 of the ref manual).

Then we can apply the above DataElementType implementation for our mappings (need to change the SqlTypes definition to this:

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

Notes:

  1. It is not perfect. There is a tendency to upcast all discrete numbers to Int64 and floats to double.

  2. There is no implicit way to store large unsigned values (e.g. values of ulong >= long.MaxValue) but this is a general sqlite problem (and possible a general ado.net problem?).

  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.

这篇关于是否可以在nhibernate中使用sqlite清单键入功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆