2010-10-13 45 views
0

J'exécute une requête qui appelle un SP, que SP renvoie des données ... mais lorsque je l'appelle avec un DataAdapter je n'obtiens aucune donnée de résultat, si j'utilise un DataReader à la place. alors j'obtiens des données. La base de données est SQL Server et le code utilise OleDb pour des raisons que je ne peux pas modifier.DataAdapter retourne un ensemble de lignes vide, mais DataReader renvoie des données

Ces deux appels renvoie les choses diférentes:

String commandText = "Declare @return_value int; exec dbo.copyTemplate ? , ? , ? , ? , ? , ? , ?, Null , 0 , @return_value;"; 

    Console.WriteLine("Data Adapter"); 
    using (OleDbConnection con = new OleDbConnection(connectionString)) 
    { 
     using (OleDbDataAdapter da = new OleDbDataAdapter(commandText, con)) 
     using (DataTable table = new DataTable("table")) 
     { 
      da.SelectCommand.Parameters.AddWithValue("?",9).DbType = DbType.Int32; 
      da.SelectCommand.Parameters.AddWithValue("?", "AAAAB").DbType = DbType.String; 
      da.SelectCommand.Parameters.AddWithValue("?", 1).DbType = DbType.Int32; 
      da.SelectCommand.Parameters.AddWithValue("?", 1).DbType = DbType.Int32; 
      da.SelectCommand.Parameters.AddWithValue("?", 2).DbType = DbType.Int32; 
      da.SelectCommand.Parameters.AddWithValue("?", true).DbType = DbType.Boolean; 
      da.SelectCommand.Parameters.AddWithValue("?", DateTime.Now.Date).DbType = DbType.DateTime; 

      da.Fill(table); 

      foreach (DataRow dr in table.Rows) 
      { 
       foreach (DataColumn dc in table.Columns) 
       { 
        Console.Write(dr[dc].ToString()); 
        Console.Write(" "); 
       } 
       Console.WriteLine(); 
      } 
     } 
    } 
    Console.WriteLine("Data Reader"); 
    using (OleDbConnection con = new OleDbConnection(connectionString)) 
    { 
     using (OleDbCommand cmd = new OleDbCommand(commandText, con)) 
     { 
      cmd.Parameters.AddWithValue("?", 9).DbType = DbType.Int32; 
      cmd.Parameters.AddWithValue("?", "AAAAC").DbType = DbType.String; 
      cmd.Parameters.AddWithValue("?", 1).DbType = DbType.Int32; 
      cmd.Parameters.AddWithValue("?", 1).DbType = DbType.Int32; 
      cmd.Parameters.AddWithValue("?", 2).DbType = DbType.Int32; 
      cmd.Parameters.AddWithValue("?", true).DbType = DbType.Boolean; 
      cmd.Parameters.AddWithValue("?", DateTime.Now.Date).DbType = DbType.DateTime; 

      con.Open(); 

      using (OleDbDataReader reader = cmd.ExecuteReader()) 
       while (reader.Read()) 
       { 
        for (int i = 0; i < reader.FieldCount; i++) 
        { 
         Console.Write(reader.GetValue(i) ?? "null"); 
         Console.Write(" "); 
        } 
        Console.WriteLine(); 
       } 
     } 
    } 

    Console.ReadKey(true); 

Ce code retourne:

Data Adapter 
Data Reader 
1057 

Je peux appeler des centaines de fois de code et je reçois toujours une valeur lecteur de données d'un rien dans les données Adaptateur, et je peux avoir n'importe quoi dans le deuxième paramètre, cela ne change rien dans le résultat du SP. Je pourrais échanger les valeurs des paramètres entre les deux appels, ou modifier l'ordre ... et le résultat serait toujours le même :(

Je ne comprends pas pourquoi est-ce qui se passe.

Quelqu'un at-il une idée ce qui pourrait être le problème

Vive

MISE à JOUR:. Si je fais un DataSet à la place un DataTable je reçois le résultat:

Console.WriteLine("Data Adapter with DataSet"); 
    using (OleDbConnection con = new OleDbConnection(connectionString)) 
    { 
     using (OleDbDataAdapter da = new OleDbDataAdapter(commandText, con)) 
     using (DataSet ds = new DataSet("table")) 
     { 
      da.SelectCommand.Parameters.AddWithValue("?",9).DbType = DbType.Int32; 
      da.SelectCommand.Parameters.AddWithValue("?", "AAAAB").DbType = DbType.String; 
      da.SelectCommand.Parameters.AddWithValue("?", 1).DbType = DbType.Int32; 
      da.SelectCommand.Parameters.AddWithValue("?", 1).DbType = DbType.Int32; 
      da.SelectCommand.Parameters.AddWithValue("?", 2).DbType = DbType.Int32; 
      da.SelectCommand.Parameters.AddWithValue("?", true).DbType = DbType.Boolean; 
      da.SelectCommand.Parameters.AddWithValue("?", DateTime.Now.Date).DbType = DbType.DateTime; 

      da.Fill(ds); 

      foreach (DataTable table in ds.Tables) 
       foreach (DataRow dr in table.Rows) 
       { 
        foreach (DataColumn dc in table.Columns) 
        { 
         Console.Write(dr[dc].ToString()); 
         Console.Write(" "); 
        } 
        Console.WriteLine(); 
       } 
     } 
    } 

Mais le DataSet ne contient qu'une seule table, donc je ne comprends toujours pas pourquoi DataAdapter.Fill (DataTable) ne fonctionne pas.

+1

Est-ce que la procédure stockée peut-être revenir plusieurs resultsets? – leppie

+0

probablement oui, comment pourrais-je le savoir? Je ne suis pas très versé dans TSQL mais dans le code je vois plusieurs instructions "select", mais je ne peux pas dire avec certitude qu'il renvoie plusieurs résultats. – vtortola

+1

J'ai vu un comportement étrange de SQL Server à ce sujet. Parfois c'est 1, parfois plus.Avez-vous essayé de ne pas donner un nom au datatable lorsque vous le construisez? – leppie

Répondre

1

Le problème est que la procédure de stockage est (comme @leppie l'a souligné) renvoyant plusieurs ensembles de résultats, le premier est vide et le second contient le résultat réel. DataAdapter.Fill (DataTable) obtient uniquement le premier jeu de résultats et le place sur un DataTable, car ce résultat est vide, vous obtenez un DataTable vide. Vous ne pouvez pas obtenir "null" car le DataTable est déjà créé, l'adaptateur remplit simplement le DataTable. DataReader passe en revue tous les ensembles de résultats, pour cette raison vous avez obtenu le résultat ici, mais il est mauvais de l'utiliser comme ça. Comme le premier jeu de résultats est null, il n'y a pas de problème pour l'instant, mais si la procédure de stockage ou la requête ad hoc renvoie plusieurs jeux de résultats, vous pouvez obtenir deux tables différentes ou plus, avec des colonnes différentes. DataAdapter.Fill (DataSet) obtient un DataTable par ensemble de résultats, comme le premier est null, et il n'y a que des données dans la seconde, vous obtenez un DataSet avec un seul DataTable.

La façon correcte et indolore de résoudre ce problème consiste à corriger la procédure stockée et à retourner un seul jeu de résultats, probablement qu'il y a quelque chose qui retourne une variable vide ou quelque chose comme ça dans le SP. Si vous souhaitez prendre en charge plusieurs ensembles de résultats, vous devrez utiliser DataAdapter.Fill (DataSet) et gérer l'idée qu'il existe peut-être plusieurs DataTable dans le DataSet rempli.

http://social.msdn.microsoft.com/Forums/en-US/adodotnetdataproviders/thread/8fdbaa2d-1f1e-461f-8505-b80ea0c415f2