Ne pas comprendre les résultats de requêtes dynamiques de Dapper dans LinqPad

dapper linqpad

Question

J'étudie l'utilisation de Dapper et j'ai essayé ceci dans LinqPad (vous devrez fournir votre propre chaîne de connexion et configurer une table 'Ticket' pour l'exécuter):

using ( var conn = new SqlConnection( builder.ToString() ) )
{
    conn.Open();
    var loadSql = 
        @"Insert into Ticket(StatusKey, Status, ContactFirstName, ContactPhoneNumber, WorkflowKey )
            Values ( @statusKey, @status, @first, @phoneNumber, @key )";
    var values = new[] 
    {
        new { statusKey = "O", status = "Open", first = "Bob", phoneNumber = "6855551425", key = "std" },
        new { statusKey = "R", status = "Researching", first = "Sue", phoneNumber = "77785552136", key = "exp" },
        new { statusKey = "OD", status = "Overdue", first = "Ted", phoneNumber = "6795551496", key = "std" },
        new { statusKey = "C", status = "Closed", first = "Mark", phoneNumber = "9945552678", key = "std" }
    };
    "Rows Added".Dump();
    conn.Execute( loadSql, values ).Dump();
    "".Dump();

    // Using <dynamic> returns same results
    var tickets = conn.Query("Select Status, ContactFirstName, ContactPhoneNumber From Ticket").ToList();
    "Tickets Found".Dump();
    tickets.Count().Dump();
    "".Dump();

    "Attempt to get first ticket".Dump();
    var firstTicket = tickets[0];
    firstTicket.Dump();
    (firstTicket ?? "first ticket is null").Dump();
    "--- End First Ticket Attempt ---".Dump();
    "".Dump();

    "Access items returned by query".Dump();
    tickets.ForEach( ticketObj => 
    {
            // ticketObj isn't null, but it not there either??
            "  Try to dump enumerated ticket".Dump();
            if(ticketObj == null) "    is null".Dump();
            ticketObj.Dump();
            //ticketObj.GetType().Dump(); // Null ref exception?
            "  --- End Enumeration Dump ---".Dump();

            // Have to cast to dictionary
            var ticket = (IDictionary<string,object>)ticketObj;
            string.Format("    {0}: {1} at {2}", ticket["Status"], ticket["ContactFirstName"], ticket["ContactPhoneNumber"]).Dump();

            "".Dump();
    });
    "--- End Access Test ---".Dump();
    "".Dump();


    conn.Execute("Truncate table ticket");
}

J'ai obtenu les résultats suivants:

Rows Added   
4

Tickets Found  
4

Attempt to get first ticket
--- End First Ticket Attempt ---

Access items returned by query
  Try to dump enumerated ticket
  --- End Enumeration Dump ---
    Open: Bob at 6855551425

  Try to dump enumerated ticket
  --- End Enumeration Dump ---
    Researching: Sue at 77785552136

  Try to dump enumerated ticket
  --- End Enumeration Dump ---
    Overdue: Ted at 6795551496

  Try to dump enumerated ticket
  --- End Enumeration Dump ---
    Closed: Mark at 9945552678

--- End Access Test ---

Comme vous pouvez le voir, les suivantes sont étranges:

  • Il me permet d'accéder au premier élément, mais il ne sera pas vidé et n'est pas nul (??) et quatre éléments sont renvoyés.
  • Lorsque j'énumère, si je lance à un IDictionary <string, object>, cela fonctionne. Mais l'élément énuméré (ticketObj) n'est pas nul, mais je ne peux pas le vider. Et si j'essaie d'obtenir son type, j'obtiens une exception de référence nulle.

Les résultats sont les mêmes si j'utilise également la version générique Query <dynamique>.

Je pensais que les résultats dynamiques étaient censés être Expandos, et je pourrais faire quelque chose comme

ticketObj.Status.Dump();

C'est-à-dire que les champs de la requête sont transformés en propriétés sur chaque objet renvoyé par Query. Qu'est-ce que je rate? Comment cela fonctionne-t-il avec la fonctionnalité dynamique de Dapper? Ou peut-être que LinqPad ne fonctionne pas avec des objets dynamiques?

Réponse acceptée

Il y a deux problèmes ici. La première est que LINQPad vide les objets dynamiques qui implémentent IDynamicMetaObjectProvider tant que IDictionary<string,object> sans pivoter au préalable pour obtenir une vue plus agréable. Cela a été corrigé pour la prochaine version.

Le second problème est que l'appel direct de Dump() sur un DapperRow échoue de manière silencieuse, au lieu de lancer l' RuntimeBinderException ('DapperRow ne contient pas de définition de "Dump"'). Cela, je pense, est une faute dans la mise en œuvre de DapperRow .

Il existe un certain nombre de solutions de contournement. Le premier, comme vous l'avez découvert, consiste à lancer en premier pour object . Une autre solution consiste à appeler directement la méthode d'extension Dump :

LINQPad.Extensions.Dump (ticketObj);

ou:

LINQPad.Extensions.Dump (ticketObj, "First ticket");

Une autre solution consiste à appeler Console.WriteLine , que LINQPad redirige vers Dump :

Console.WriteLine (ticketObj);

Réponse populaire

J'ai déterminé qu'il s'agissait d'un problème LinqPad. Comme il utilise des méthodes d'extension, il ne peut pas vraiment gérer les types dynamiques. Cependant, si vous convertissez la dynamique en objet, cela fonctionne. Donc, si vous remplacez

firstTicket.Dump();

avec

((object)firstTicket).Dump();

ça marche ... en quelque sorte. Il montre un IDictionary avec les colonnes de la requête. LinqPad n'a aucun moyen de savoir quelles sont les colonnes ajoutées dynamiquement. Voir SO cette réponse pour plus d'informations.

Cette même technique a également fonctionné lors du dénombrement. Si je change

ticketObj.Dump();

à

((object)ticketObj).Dump();

Ça marche. Je peux aussi accéder aux propriétés dynamiques, je dois juste les lancer en premier.

((string)ticketObj.Status).Dump();

Le .GetType () ne semble pas fonctionner avec les types dynamiques ... Je ne pense pas qu'ils en aient un. Notez bien si cela est correct, mais cela ne fonctionnait pas non plus dans une application de console VS normale.



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