2014-06-05 9 views
8

Ich habe eine ziemlich Agnostiker ADO.NET-Anwendung, die auf eine Reihe von Datenbanken verbindet und in der Lage, die notwendigen Informationen zu extrahieren, zu laufen. Ich habe einen Haken mit DB2 und wie es benannte Parameter behandelt, insbesondere wenn ich einen benannten Parameter in derselben Abfrage wiederverwende. Ich kenne einige Möglichkeiten, um dies zu umgehen, indem ich einfach weitere Parameter hinzufüge, aber in der Theorie sollte es so funktionieren wie bei anderen Datenbanken, mit denen ich mich verbinde, da der Parametername derselbe ist.C# ADO.NET IBM DB2 benannte Parameter mit dem gleichen Namen führen Nicht genügend Parameter angegeben Ausnahme

Was ich tue, ist ein bisschen komplizierter und beinhaltet Unterabfragen usw., sondern zu zeigen, nehmen Sie die folgende Abfrage:

Auswahlwert von test.table wo Cola = @ key1 und colb = @ Schlüssel1;

Der benannte Parameter @ key1 wird zweimal verwendet.

Mein Code ist wie folgt:

 try 
     { 
      DbProviderFactory dbfFactory = DbProviderFactories.GetFactory("IBM.Data.DB2.iSeries"); 
      using (DbConnection dbConnection = dbfFactory.CreateConnection()) 
      { 
       dbConnection.ConnectionString = "DataSource=xxx.xxx.xxx.xxx;UserID=xxxxxxxx;password=xxxxxxxxx"; 

       using (DbCommand dbCommand = dbConnection.CreateCommand()) 
       { 
        IDbDataParameter iddpParameter1 = dbCommand.CreateParameter(); 
        iddpParameter1.ParameterName = "@key1"; 
        iddpParameter1.DbType = DbType.String; 
        iddpParameter1.Value = "1"; 

        dbCommand.Parameters.Add(iddpParameter1); 
        dbCommand.CommandType = CommandType.Text; 
        dbCommand.CommandText = "select value from test.table where [email protected] and [email protected]"; 
        dbConnection.Open(); 

        using (IDataReader idrReader = dbCommand.ExecuteReader()) 
        { 
         while (idrReader.Read()) 
         { 
            ... 
         } 
        } 
       } 

      } // end dbConnection 
     } // end try 

     catch (Exception ex) 
     { 
      Console.Write(ex.Message); 
     } 

Als ich das laufen bekomme ich eine Ausnahme, die mir sagt:

System.InvalidOperationException: Not enough parameters specified. The command requires 2 parameter(s), but only 1 parameter(s) exist in the parameter collection. 

ich bekommen, was es sagt mir, aber ich bin auf der Suche nach helfen, herauszufinden, wie ich den Provider den benannten Parameter für beide Parameter verwenden kann, da sie identisch sind. Es scheint, dass es eine blinde Zählung benannter Parameter macht und nicht merkt, dass sie die gleichen benannten Parameter sind. SQL Server scheint mir das mit dem gleichen Code oben zu ermöglichen. Ich vermute, dass es nur einer dieser Unterschiede in den Anbietern ist, aber ich hoffe, dass jemand darauf gestoßen ist und eine Lösung für DB2 hat, die nicht in spezifischen DB2-Code eingeht.

Danke, schätze die Hilfe.

+0

Haben Sie jemals eine Lösung für dieses Problem gefunden? Wir haben das gleiche Verhalten – Andronicus

+0

Leider habe ich keine Lösung gefunden. Ich musste einen anderen benannten Parameter erstellen und ihm einfach den gleichen Wert zuweisen. – Brent

+1

Interessant. Da ADO.NET ziemlich neu ist, habe ich noch nicht erkannt, dass ein .NET-Anbieter die Verwendung von benannten Parametern mit DB2 für i ermöglicht. DB2 unter IBM i verwendet '?' [Parametermarker] (http://www-01.ibm.com/support/knowledgecenter/ssw_ibm_i_71/db2/rbafzpreph2.htm). Ich nehme an, dass ein Layer auf der Windows-Seite den benannten Parameter in ein Fragezeichen übersetzt, bevor er die Anfrage an den Server sendet. – WarrenT

Antwort

0

Nun, ich habe ein wenig mehr graben, und ich frage mich, ob es der Stecker sein könnte, den Sie verwenden. Also mache ich die folgenden (die sehr ähnlich ist, was Sie tun)

in meiner app config-Datei Ich habe

<connectionStrings> 
    <add name="AWOLNATION" providerName="Ibm.Data.DB2" connectionString="Server=sail:50000;Database=Remix;" /> 
</connectionStrings> 

in meiner DatabaseManager- Klasse würde ich es initialisieren wie so

public static DatabaseManager Instance(string connectionStringName) 
    { 
     var connectionStringSettings = ConfigurationManager.ConnectionStrings[connectionStringName]; 
     if (connectionStringSettings == null) throw new MissingMemberException("[app.config]", string.Format("ConnectionStrings[{0}]", connectionStringName)); 
     return new DatabaseManager(connectionStringSettings); 
    } 

    private DatabaseManager(ConnectionStringSettings connectionInformation) 
    { 
     _connectionInformation = connectionInformation; 
     _parameters = new Dictionary<string, object>(); 
    } 
    private void Initialize() 
    { 
     _connection = DbProviderFactories.GetFactory(_connectionInformation.ProviderName).CreateConnection(); 
     _connection.ConnectionString = _connectionInformation.ConnectionString; 

     _command = _connection.CreateCommand(); 
    } 

Ich füge Parameter etwas anders hinzu. Ich habe eine Dictionary<string,object>, die ich auch bei der Einrichtung meiner Abfrage hinzufügen. Um Ihrem Beispiel verwende ich hätte, wenn diese

public IEnumerable<object> GetSomething(string key) 
    { 
     var sql = "select value from test.table where cola = @key1 and colb = @key1"; 
     _manager.AddParameter("@key1", key); 

     return _manager.ExecuteReader<object>(sql, ToSomethignUseful); 
    } 

    private object ToSomethignUseful(DatabaseManager arg) 
    { 
     return new { Value = arg.GetArgument<object>("value") }; 
    } 

dann zu lesen ist, wo die OP und ich habe einen ähnlichen Code

public IEnumerable<T> ExecuteReader<T>(string sql, Func<DatabaseManager, T> conversionBlock) 
    { 
     Initialize(); 
     using (_connection) 
     { 
      _connection.Open(); 
      _command.CommandText = sql; 
      _command.CommandType = CommandType.Text; 

      if (_parameters.Count > 0) 
       AddParameters(_command, _parameters); 

      _parameters.Clear(); 

      using (_reader = _command.ExecuteReader()) 
      { 
       while (_reader.Read()) 
       { 
        yield return conversionBlock(this); 
       } 
      } 
     } 
    } 
    private static void AddParameters(DbCommand command, Dictionary<string, object> parameters) 
    { 
     foreach (var param in parameters) 
     { 
      command.Parameters.Add(CreateParameter(command, param.Key, param.Value)); 
     } 
    } 

    private static DbParameter CreateParameter(DbCommand command, string key, object value) 
    { 
     var parameter = command.CreateParameter(); 
     parameter.ParameterName = key; 
     parameter.Value = value; 

     return parameter; 
    } 

Betreiben des Code für mich arbeitet, so frage ich mich, wenn die Differenz in der Anbieter, den wir verwenden. Ich benutze benannte Parameter in der Produktion und bin seit mindestens einem Jahr, vielleicht näher bei 2 Jahren.

Ich werde sagen, dass ich den gleichen Fehler haben, wenn im Wesentlichen zweimal den gleichen Code ausgeführt wird, wie in diesem Code gezeigt

public static void IndendedPrintForEach<T>(this IEnumerable<T> array, string header, Func<T, string> consoleStringConverterMethod) 
    { 
     var list = array.ToList(); 
     var color = Console.ForegroundColor; 
     Console.ForegroundColor = ConsoleColor.Magenta; 
     Console.WriteLine($"<<<{header}>>>"); 
     Console.ForegroundColor = color; 

     if (!list.Any()) 
     { 
      Console.ForegroundColor = ConsoleColor.DarkRed; 
      Console.WriteLine(" ************NoItemsFound************"); 
      Console.ForegroundColor = color; 
     } 
     else 
     { 
      foreach (var item in list) 
       Console.WriteLine($" {consoleStringConverterMethod(item)}"); 
     } 
    } 

auf Linie 3 var list = array.ToList() das Update für das Problem war, dass Sie für mich zu sehen waren .vorher hatte ich , die die Abfrage ausführen und die Parameter verwenden würde (die ich lösche, bevor ich die Abfrage erhalte), als ich gehe, um jedes Einzelteil im Array aufzuzählen und zu drucken, erhielt ich dann den Fehler. Für mich bestand das Problem darin, dass die Abfrage erneut ausgeführt wurde, dass ich keine Parameter mehr hatte. Die Lösung bestand darin, die Abfrage mit der ToList() aufzulisten und dann die Liste zu überprüfen und zu drucken.

Verwandte Themen