Pergunta

este foi postada no hibernate.org fóruns e nhusers lista sem muita sorte, então eu pensei que eu iria tentar aqui.

Em termos simples, suponha que eu tenho uma classe:

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

o tipo de SomeValue é basicamente no conjunto de tipos de NET IConvertible (primitivos como booleano, byte, carvão animal, int16, duplo, flutuar, etc.), mais byte [] e corda.

Eu estou tentando criar um mapeamento nhibernate para A para refletir isso - para que eu possa basicamente definir SomeValue a um objeto arbitrária (de um dos tipos acima) e recuperá-lo mais tarde em diante. Meu AppLogic, então, refletir sobre ela para encontrar o tipo e agir em conformidade.

Até agora eu tentei criar uma implementação de IUserType para tentar lidar com isso. No entanto, eu não sei o que para voltar para os SQLTYPE [] SqlTypes. I considerado novo SQLTYPE (DbType.Object), mas quando tento gerar um esquema deste recebo uma System.ArgumentException: O Dialect não suporta DbType.Object

Se eu tentar outro tipo de dados, em seguida, eu recebo várias exceções elenco ao tentar converter o tipo. Por exemplo, se eu usar um DbType.Binary e conjunto someValue a um int32, após a tentativa de cometer fico System.InvalidCastException:. Não é possível para objeto fundido do tipo 'System.Int32' para digitar 'System.Byte []'

Existe uma maneira de conseguir isso?

código anexado abaixo para uma aplicação não-trabalho de IUserType (baseado em 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;
        }
    }
Foi útil?

Solução

Acontece que para contornar o problema com SQLTYPE (DbType.Object) sendo suportado pela Dialect, nós torná-lo apoiado por subclasse o SQLiteDialect com apoio explícito:

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

Para usar este dialeto em Fluente, chamar Dialect () em seu objeto SQLiteConfiguration. Em NHibernate, defina o dialeto propriedade de configuração appropriatelly (ver secção 3.5.1 do manual ref).

Então, podemos aplicar o acima DataElementType implementação para nossos mapeamentos (necessidade de mudar a definição SqlTypes a esta:

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

Notas:

  1. Não é perfeito. Há uma tendência para upcast todos os números discretos para Int64 e flutua para o dobro.

  2. Não há nenhuma maneira implícita para armazenar grandes valores sem sinal (por exemplo, valores de ulong> = long.MaxValue), mas este é um problema sqlite geral (e possível um problema geral ado.net?).

  3. Devido à perda de tempo de compilação verificação é provavelmente desejável para colocar algumas verificações de tempo de execução no método NullSafeSet para garantir o valor é um tipo primitivo. A tentativa de armazenar objetos gerais parece justa causa os objetos ToString () método a ser chamado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top