Domanda

questo è stato pubblicato sui forum di hibernate.org e sulla lista dei nhusers senza molta fortuna, quindi ho pensato di provare qui.

In parole semplici, supponiamo che io abbia una classe:

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

il tipo di SomeValue è sostanzialmente nell'insieme dei tipi .NET IConvertible (primitive come bool, byte, char, int16, double, float ecc.), più byte [] e stringa.

Sto cercando di creare una mappatura proibitiva per A per riflettere questo - in modo da poter sostanzialmente impostare SomeValue su un oggetto arbitrario (di uno dei tipi sopra) e recuperarlo in seguito. Il mio applogic rifletterà quindi su di esso per trovare il tipo e comportarsi di conseguenza.

Finora ho provato a creare un'implementazione di IUserType per provare a gestirlo. Tuttavia, non so cosa restituire per SqlType [] SqlTypes. Ho considerato il nuovo SqlType (DbType.Object) ma quando provo a generare uno schema da questo ottengo un System.ArgumentException: Dialect non supporta DbType.Object

Se provo un altro tipo di dati, ottengo varie eccezioni di cast quando provo a convertire il tipo. Ad esempio, se utilizzo DbType.Binary e imposto someValue su int32, dopo aver tentato di eseguire il commit ottengo System.InvalidCastException: impossibile eseguire il cast di oggetti di tipo 'System.Int32' per digitare 'System.Byte []'.

C'è un modo per raggiungere questo obiettivo?

Codice allegato di seguito per un'implementazione non funzionante di IUserType (basato su 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;
        }
    }
È stato utile?

Soluzione

Risulta per ovviare al problema con SqlType (DbType.Object) non supportato dal dialetto, lo rendiamo supportato subclassando SQLiteDialect con supporto esplicito:

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

Per usare questo dialetto in Fluente, chiama Dialect () sul tuo oggetto SQLiteConfiguration. In NHibernate, impostare il dialetto della proprietà di configurazione in modo appropriato (vedere la sezione 3.5.1 del manuale di riferimento).

Quindi possiamo applicare l'implementazione DataElementType sopra per i nostri mapping (è necessario modificare la definizione SqlTypes in questo:

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

Note:

  1. Non è perfetto. C'è una tendenza a trasferire tutti i numeri discreti su Int64 e float per raddoppiare.

  2. Non esiste un modo implicito per memorizzare valori non firmati di grandi dimensioni (ad esempio valori di ulong > = long.MaxValue) ma questo è un problema sqlite generale (e forse un problema generale ado.net?).

  3. A causa della perdita del controllo del tempo di compilazione, è probabilmente desiderabile inserire alcuni controlli di runtime nel metodo NullSafeSet per assicurarsi che il valore sia di tipo primitivo. Tentare di archiviare oggetti generali sembra causare solo il metodo ToString () degli oggetti da chiamare.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top