Pregunta

esto se publicó en los foros de hibernate.org y en la lista de usuarios sin mucha suerte, así que pensé en intentarlo aquí.

En pocas palabras, supongamos que tengo una clase:

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

el tipo de SomeValue está básicamente en el conjunto de tipos .NET IConvertible (primitivas como bool, byte, char, int16, double, float, etc.), más byte [] y cadena.

Estoy tratando de crear un mapeo nhibernate para que A refleje esto, de modo que básicamente pueda establecer SomeValue en un objeto arbitrario (de uno de los tipos anteriores) y recuperarlo más adelante. Mi aplicación se reflejará en ella para encontrar el tipo y comportarse en consecuencia.

Hasta ahora he intentado crear una implementación de IUserType para tratar de manejar esto. Sin embargo, no sé qué devolver para los SqlType [] SqlTypes. Considere un nuevo SqlType (DbType.Object) pero cuando trato de generar un esquema a partir de esto obtengo un System.ArgumentException: Dialect no es compatible con DbType.Object

Si intento otro tipo de datos, obtengo varias excepciones de conversión al intentar convertir el tipo. Por ejemplo, si uso un DbType.Binary y establezco someValue en int32, al intentar confirmar obtengo System.InvalidCastException: No se puede emitir un objeto de tipo 'System.Int32' para escribir 'System.Byte []'.

¿Hay alguna manera de lograr esto?

Código adjunto a continuación para una implementación no funcional de IUserType (basado en 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;
        }
    }
¿Fue útil?

Solución

Resulta solucionar el problema de que SqlType (DbType.Object) no es compatible con Dialect, lo hacemos compatible subclasificando SQLiteDialect con soporte explícito:

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

Para usar este dialecto en Fluent, llame a Dialect () en su objeto SQLiteConfiguration. En NHibernate, establezca el dialecto de propiedad de configuración de manera apropiada (consulte la sección 3.5.1 del manual de referencia).

Entonces podemos aplicar la implementación DataElementType anterior para nuestras asignaciones (es necesario cambiar la definición de SqlTypes a esto:

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

Notas:

  1. No es perfecto. Hay una tendencia a subir todos los números discretos a Int64 y los flotantes a duplicar.

  2. No hay una forma implícita de almacenar grandes valores sin signo (por ejemplo, valores de ulong > = long.MaxValue), pero este es un problema general de sqlite (¿y posible un problema general de ado.net?).

  3. Debido a la pérdida de tiempo de compilación, es probable que sea conveniente realizar algunas comprobaciones de tiempo de ejecución en el método NullSafeSet para garantizar que el valor sea un tipo primitivo. Intentar almacenar objetos generales parece causar que se invoque el método ToString () de objetos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top