Error de conversión anulable .NET Dapper

.net dapper nullable orm

Pregunta

Usando .NET Dapper, estoy teniendo un problema al obtener un campo de base de datos que contenga un valor entero (0/1) para mapear una propiedad booleana anulable en una clase.

Para mantener las cosas simples, me he despojado y he cambiado el nombre de la clase al mínimo necesario para reproducir el problema:

public class Test
{
    public bool? TestField { get; set; }
}

Si se llama al siguiente código para llenar la clase de prueba:

var Results = DBConnection.Query<Test>("SELECT 0 As TestField]").ToList();

el siguiente error será lanzado:

Invalid cast from 'System.Int32' to 'System.Nullable`1[[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]

Si elimino el signo de interrogación, haciendo que el campo sea booleano no nulable (es decir, bool TestField), todo funciona bien.

La respuesta inmediata puede parecer eliminar el nulo y llamarlo un día. Sin embargo, la razón por la que esto no funcionará es porque estamos usando esta misma clase para serializar registros hacia y desde un servicio web, y necesitamos poder distinguir entre falso y nulo. Pensé en tener dos clases, una con tipos de propiedades que aceptan valores nulos, y otra sin ella, pero luego tengo la sobrecarga adicional de mantener dos clases en lugar de una.

Una transformación de datos personalizada durante un conjunto de propiedades sería ideal. Sin embargo, no he encontrado nada en la documentación apresurada que sugiera que esto sea posible.

Respuesta aceptada

Parece que puede haber un problema en el código Dapper con respecto a bool / largo nullable, etc.

Aquí hay tres líneas del código fuente (líneas 2375-2377 versión 1.12.1.1). El problema está en la primera línea:

il.Emit(OpCodes.Ldtoken, unboxType); // stack is now [target][target][value][member-type-token]
il.EmitCall(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"), null); // stack is now [target][target][value][member-type]
il.EmitCall(OpCodes.Call, typeof(Convert).GetMethod("ChangeType", new Type[] { typeof(object), typeof(Type) }), null); // stack is now [target][target][boxed-member-type-value]

Cuando se emite este código, se convierte en equivalente a la siguiente línea de código:

Convert.ChangeType(0, typeof(bool?));

Desafortunadamente, esto arroja el error que estoy viendo. Al cambiar la primera línea il.Emit () de arriba a la siguiente:

il.Emit(OpCodes.Ldtoken, nullUnderlyingType ?? memberType); // stack is now [target][target][value][member-type-token]

La línea de código equivalente generada se convierte en esto, teniendo en cuenta que el tipo de (bool?) Al final ya no tiene el signo de interrogación con nulos después de él:

Convert.ChangeType(0, typeof(bool));

Esta línea de código no arroja un error.

Entonces la solución fue una recompilación de la fuente. Enviaré este cambio al proyecto para que lo revisen y vean si esto causará algún efecto secundario no deseado.


Respuesta popular

Bit debe mapear bien en bool:

create table Test
(
    TestField bit null
)

Otra opción sería hacer algo como:

var Results = DBConnection.Query<Test>("SELECT cast(case TestField when 1 then 1 when 0 then 0 else null end as bit)  As TestField from Test").ToList();


Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow