Erreur de conversion nullable de .NET Dapper

.net dapper nullable orm

Question

En utilisant .NET Dapper, j'ai un problème pour obtenir un champ de base de données contenant une valeur entière (0/1) pour mapper une propriété booléenne nullable dans une classe.

Pour garder les choses simples, j'ai dénudé et renommé la classe au strict minimum nécessaire pour reproduire le problème:

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

Si le code suivant est appelé pour remplir la classe Test:

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

l'erreur suivante sera levée:

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

Si je supprime le point d'interrogation, faisant du champ un booléen non nullable (par exemple, bool public TestField), tout fonctionne bien.

La réponse immédiate peut apparaître pour supprimer le nullable et l'appeler un jour. Cependant, la raison pour laquelle cela ne fonctionnera pas est que nous utilisons cette même classe pour sérialiser les enregistrements vers et depuis un service Web, et nous devons être en mesure de faire la différence entre false et null. J'ai pensé à avoir deux classes, une avec des types de propriété nullables, et une sans, mais j'ai la surcharge supplémentaire de maintenir deux classes au lieu d'une.

Une transformation de données personnalisée au cours d'un ensemble de propriétés serait idéale. Cependant, je n’ai rien trouvé dans la documentation épineuse pour suggérer que cela est même possible.

Réponse acceptée

On dirait qu’il peut y avoir un problème dans le code Dapper en ce qui concerne null / bool / long, etc.

Voici trois lignes du code source (lignes 2375-2377 version 1.12.1.1). Le problème est sur la première ligne:

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]

Lorsque ce code est émis, il devient équivalent à la ligne de code suivante:

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

Malheureusement, cela jette l'erreur que je vois. En modifiant la première ligne il.Emit () ci-dessus, procédez comme suit:

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

La ligne de code équivalente générée devient ceci, en notant le typeof (bool?) À la fin n'a plus le point d'interrogation nullable après lui:

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

Cette ligne de code ne génère pas d'erreur.

La solution était donc une recompilation de la source. Je soumettrai ce changement au projet pour qu'ils examinent si cela risque d'entraîner des effets secondaires indésirables.


Réponse populaire

Bit devrait bien mapper dans bool:

create table Test
(
    TestField bit null
)

Une autre option serait de faire quelque chose comme:

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();


Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi