é possível usar os recursos de digitação manifestam SQLite no nhibernate?
-
06-07-2019 - |
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;
}
}
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:
-
Não é perfeito. Há uma tendência para upcast todos os números discretos para Int64 e flutua para o dobro.
-
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?).
-
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.