2017-08-08 2 views
1

J'exécute une procédure stockée en utilisant QueryMultiple pour renvoyer plusieurs ensembles de données.QueryMultiple Résultat Set Order

var gridReader = db.QueryMultiple("sp", 
            parameters, 
            commandType: CommandType.StoredProcedure); 

Je peux très facilement obtenir chaque jeu étant donné que je sais que l'ordre dans lequel ils reviendront dans.

SELECT * FROM dbo.Set1; 
SELECT * FROM dbo.Set2; 
SELECT * FROM dbo.Set3; 
var set1 = gridReader.Read<Set1>(); 
var set2 = gridReader.Read<Set2>(); 
var set3 = gridReader.Read<Set3>(); 

Cependant, je suis dans une situation où l'ordre reviendra en mai changer. Un autre développeur pourrait décider de changer la commande pour une raison quelconque. La procédure stockée devient maintenant ceci:

SELECT * FROM dbo.Set1; 
SELECT * FROM dbo.Set3; 
SELECT * FROM dbo.Set2; 

Comment puis-je gérer cela?

Ma tentative initiale consistait à itérer chaque grille en vérifiant les noms des colonnes. Cela a semblé bien fonctionner au début, mais je n'ai pas réussi à comprendre comment projeter la grille dans une classe, en plus de définir manuellement chaque champ. La principale raison pour laquelle j'utilise Dapper est qu'il peut le faire pour moi.

while (true) 
{ 
    var grid = gridReader.Read(); 
    IDictionary<string, object> row = grid.FirstOrDefault(); 

    if (row == null) 
     break; 

    if (row.Keys.Contains("Set1_UniqueColumnName")) 
    { 
     // Need something like grid.Read<Set1>(); 
    } 
    else if (row.Keys.Contains("Set2_UniqueColumnName")) { } 
    else if (row.Keys.Contains("Set3_UniqueColumnName")) { } 
} 

Ma deuxième idée était de lire chaque grille dans une classe, vérifiez les champs uniques de la classe pour les valeurs NULL/valeurs par défaut, et d'essayer la classe suivante si le test a échoué. Cela ne fonctionnera évidemment pas bien. .Read() renverra la grille suivante. Cette solution exigerait que je puisse lire la même grille encore et encore.

Répondre

1

Davmos's answer m'a pointé dans la bonne direction. Nécessaire d'utiliser une combinaison de ADO.NET et Dapper. Essentiellement utiliser ADO.NET pour récupérer et parcourir les données, mais utiliser Dapper pour analyser les lignes dans mes objets. Notez l'utilisation de FieldCount dans la boucle while dans le cas où un jeu de résultats renvoie effectivement 0 lignes. Nous voulons qu'il passe à l'ensemble de résultats suivant, ne pas sortir de la boucle.

Set1 set1 = null; 
var set2 = new List<Set2>(); 
Set3 set3 = null; 

using (var command = new SqlCommand("sp", conn)) 
{ 
    command.CommandType = CommandType.StoredProcedure; 
    command.Parameters.AddRange(parameters); 
    command.Connection.Open(); 

    using (var reader = command.ExecuteReader()) 
    { 
     while (reader.FieldCount > 0) 
     { 
      var set1Parser = reader.GetRowParser<Set1>(); 
      var set2Parser = reader.GetRowParser<Set2>(); 
      var set3Parser = reader.GetRowParser<Set3>(); 

      var isSet1 = HasColumn(reader, "Set1_UniqueColumnName"); 
      var isSet2 = HasColumn(reader, "Set2_UniqueColumnName"); 
      var isSet3 = HasColumn(reader, "Set3_UniqueColumnName"); 

      while (reader.Read()) 
      { 
       if (isSet1) 
       { 
        set1 = set1Parser(reader); 
       } 
       else if (isSet2) 
       { 
        set2.Add(set2Parser(reader)); 
       } 
       else if (isSet3) 
       { 
        set3 = set3Parser(reader); 
       } 
      } 

      reader.NextResult(); 
     } 
    } 
} 
public static bool HasColumn(IDataReader reader, string columnName) 
{ 
    for (var i = 0; i < reader.FieldCount; i++) 
    { 
     if (reader.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase)) 
     { 
      return true; 
     } 
    } 

    return false; 
} 
2

Dapper fournit une méthode d'extension IDataReader.GetRowParser qui permet le changement de type par ligne. De la documentation Dapper here ...

vous voulez aurez généralement traiter toutes les lignes d'une table donnée le même type de données . Cependant, dans certaines circonstances, il est utile de pouvoir analyser différentes lignes en tant que types de données différents. C'est là que IDataReader.GetRowParser est très pratique.

Imaginez que vous avez une table de base de données nommée « Formes » avec les colonnes: Id, type et de données, et que vous souhaitez analyser ses lignes dans le cercle, Carré ou objets Triangle en fonction de la valeur de la colonne Type .

var shapes = new List<IShape>(); 
using (var reader = connection.ExecuteReader("select * from Shapes")) 
{ 
    // Generate a row parser for each type you expect. 
    // The generic type <IShape> is what the parser will return. 
    // The argument (typeof(*)) is the concrete type to parse. 
    var circleParser = reader.GetRowParser<IShape>(typeof(Circle)); 
    var squareParser = reader.GetRowParser<IShape>(typeof(Square)); 
    var triangleParser = reader.GetRowParser<IShape>(typeof(Triangle)); 

    var typeColumnIndex = reader.GetOrdinal("Type"); 

    while (reader.Read()) 
    { 
     IShape shape; 
     var type = (ShapeType)reader.GetInt32(typeColumnIndex); 
     switch (type) 
     { 
      case ShapeType.Circle: 
       shape = circleParser(reader); 
       break; 
      case ShapeType.Square: 
       shape = squareParser(reader); 
       break; 
      case ShapeType.Triangle: 
       shape = triangleParser(reader); 
       break; 
      default: 
       throw new NotImplementedException(); 
     } 

     shapes.Add(shape); 
    } 
} 

Vous aurez besoin d'avoir accès au IDataReader que les GridReader enveloppements ou changer votre code pour utiliser la bonne ADO.NET ancienne SqlConnection & SqlCommand objets comme ça ...

using (command = new SqlCommand("sp", connection)) 
{ 
    command.CommandType = CommandType.StoredProcedure; 
    command.Parameters.AddRange(parameters); 

    using (var reader = command.ExecuteReader()) 
    { 
     while (reader.HasRows) 
     { 
      while(reader.Read()) 
      { 

      } 

      reader.NextResult(); 
     } 
    } 
} 
+0

Merci de me pointer dans la bonne direction! Je pensais que j'allais avoir besoin de 'GetRowParser' d'une façon ou d'une autre mais je n'arrivais pas à le comprendre. Combiner cela avec un SqlDataReader a fait l'affaire. –

+0

Vous êtes les bienvenus :) Bravo! – davmos