Question

cela a été posté sur les forums hibernate.org et la liste des nhusers sans grande chance, alors j’ai pensé que j’essaierais ici.

En d'autres termes, supposons que j'ai une classe:

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

le type de SomeValue est essentiellement dans l'ensemble des types .NET IConvertible (primitives telles que bool, byte, char, int16, double, float, etc.), plus byte [] et string.

J'essaie de créer un mappage nhibernate pour A afin de refléter ceci - afin de pouvoir définir en gros SomeValue sur un objet arbitraire (de l'un des types ci-dessus) et de le récupérer plus tard. Mon application réfléchira ensuite pour trouver le type et se comporter en conséquence.

Jusqu'à présent, j'ai essayé de créer une implémentation de IUserType pour essayer de gérer cela. Cependant, je ne sais pas quoi retourner pour les SqlType [] SqlTypes. J'ai envisagé un nouveau SqlType (DbType.Object), mais lorsque j'essaie de générer un schéma à partir de celui-ci, je reçois une exception System.ArgumentException: Dialect ne prend pas en charge DbType.Object

Si j'essaie un autre type de données, différentes exceptions de transtypes apparaissent lorsque je tente de convertir le type. Par exemple, si j'utilise un DbType.Binary et que someValue est défini sur un int32, lors de la tentative de validation, j'obtiens System.InvalidCastException: impossible de convertir l'objet de type 'System.Int32' à 'System.Byte []'.

Y a-t-il un moyen d'y parvenir?

Code ci-dessous pour une implémentation non fonctionnelle de IUserType (basé sur 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;
        }
    }
Était-ce utile?

La solution

Il s'avère que le problème vient du fait que SqlType (DbType.Object) n'est pas pris en charge par le dialecte, nous le prenons en charge en sous-classant SQLiteDialect avec un support explicite:

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

Pour utiliser ce dialecte dans Fluent, appelez Dialect () sur votre objet SQLiteConfiguration. Dans NHibernate, définissez le dialecte de la propriété de configuration de manière appropriée (voir la section 3.5.1 du manuel de référence).

Ensuite, nous pouvons appliquer l'implémentation DataElementType ci-dessus pour nos mappages (il est nécessaire de modifier la définition de SqlTypes en ceci:

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

Notes:

  1. Ce n'est pas parfait. Il existe une tendance à la conversion ascendante de tous les nombres discrets vers Int64 et la double à la flottille.

  2. Il n'y a pas de moyen implicite de stocker de grandes valeurs non signées (par exemple, les valeurs de ulong > = long.MaxValue), mais il s'agit d'un problème général de SQLite (et éventuellement d'un problème général d'ado.net?).

  3. En raison de la perte de vérification du temps de compilation, il est probablement souhaitable de mettre en place des vérifications d'exécution dans la méthode NullSafeSet pour vous assurer que la valeur est un type primitif. Tenter de stocker des objets généraux semble provoquer simplement l’appel de la méthode des objets ToString ().

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top