2 Stimmen

Parameterbenennung mit System.Data.Common

Dies ist wahrscheinlich ein Oldie-aber-Goodie. Ich verwende System.Data.Common für eine austauschbare Oracle/SQL Server/SQLite-Datenzugriffsbibliothek. Während des Konstruktors nehme ich den Namen der Verbindungszeichenfolge und verwende diesen, um den zugrunde liegenden Providertyp zu bestimmen. Der Grund, warum ich dies tue, ist die unterschiedlichen IDbParameter-Namenskonventionen für jeden Anbieter zu behandeln. Oracle mag zum Beispiel :parameter, während SQL Server und SQLite @parameter bevorzugen. Der Standardwert ist ?, um Oledb abzudecken.

Frage: Ist das alles unnötig und gibt es eine einfache Sache, die ich übersehe, die sich einfach darum kümmern sollte? Wenn mein IDbCommand.CommandText = "select id, name from my.table where id = :id" ist, bin ich dann sicher? Im Moment nehme ich nur ? als Standard und dann RegEx'ing meinen Weg zum richtigen Parameter-Bezeichner vor der Ausführung des Befehls.

Danke.

        /// <summary>
    /// Initializes a new instance of the <see cref="RelationalGateway"/> class.
    /// </summary>
    /// <remarks>You must pass in the name of the connection string from the application configuration
    /// file rather than the connection string itself so that the class can determine
    /// which data provider to use, e.g., SqlClient vs. OracleClient.</remarks>
    public RelationalGateway(string connectionStringName)
    {
        if (string.IsNullOrEmpty(connectionStringName)) throw new ArgumentNullException("connectionStringName");
        if (ConfigurationManager.ConnectionStrings[connectionStringName] == null ||
            ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString.Length == 0 ||
            ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName.Length == 0)
        {
            throw new InvalidOperationException(string.Format(
                                                    "The configuration file does not contain the {0} connection ",
                                                    connectionStringName) +
                                                "string configuration section or the section contains empty values. Please ensure the " +
                                                "configuration file has the appropriate values and try again.");
        }

        _connectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
        _providerName = ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName;
        _theProvider = DbProviderFactories.GetFactory(_providerName);
        _adapter = _theProvider.CreateDataAdapter();
        //GetConnection();
        DetermineProviderSpecificParameters();
    }

Das Bit DetermineProviderSpecificParameters ermittelt im Grunde genommen "?" oder ":" oder "@" oder etwas anderes.

UPDATE Hier ist, wie ich bisher mit den Details umgegangen bin:

  1. Holen Sie sich den richtigen Parameterstring:

    private void DetermineProviderSpecificParameters() { // Prüfung auf unterstützte Anbieter. Dies dient dazu, dass parametrisierte Abfragen zur Einschränkung // nach räumlicher Ausdehnung korrekt erstellt werden. string shortName = _providerName.Substring(_providerName.LastIndexOf(".") + 1);

        switch (shortName)
        {
            case "SqlClient":
                _param = "@";
                _ql = "[";
                _qr = "]";
                break;
            case "SQLite":
                _param = "@";
                _ql = string.Empty;
                _qr = string.Empty;
                break;
            case "OracleClient":
                _param = ":";
                _ql = string.Empty;
                _qr = string.Empty;
                break;
            default:
                _param = "?";
                _ql = string.Empty;
                _qr = string.Empty;
                break;
        }
    }
  2. ein kleines Hilfsprogramm aufrufen, bevor ich jeden Befehl ausführe, um ihn zu "bereinigen" oder zu "parametrisieren" oder wie auch immer wir diesen halbherzigen Hack nennen:

    private void MakeProviderSpecific(IDbCommand command)
    {
        foreach (IDataParameter param in command.Parameters)
        {
            param.ParameterName = GetProviderSpecificCommandText(param.ParameterName);
        }
        command.CommandText = GetProviderSpecificCommandText(command.CommandText);
    }
  3. Und dies ruft eine kleine Regex zu tun, zu tun:

    public string GetProviderSpecificCommandText(string rawCommandText)
    {
        return Regex.Replace(rawCommandText, @"\B\?\w+", new MatchEvaluator(SpecificParam));
    }

Igitt. Ich suche immer noch nach einer relativ einfachen Lösung, aber die bisherigen Ratschläge sind sehr willkommen.

1voto

nos Punkte 214143

Es scheint keine Konvention oder API dafür zu geben. ORMs wie nhibernate implementiert auch ihre eigene Zuordnung der Platzhalter-Präfix für jeden Treiber.

1voto

Mac Punkte 7951

Ich habe etwas Ähnliches gemacht für Salamanca : siehe ParameterBuilder.cs . Dieser Code verwendet :

Das Problem ist, dass Sie einen gültigen Namen für Ihren Parameter benötigen ( "@name" in Sql Server, "name" in Oracle), und einen gültigen Platzhalter in Ihrer SQL-Abfrage ( "@name" in Sql Server, ":name" in Oracle).

  1. Mit einer richtigen Verbindung, GetParameterName gibt Ihnen einen gültigen Namen für Ihren Parameter.
  2. Erstellen Sie Ihren Platzhalter :

    • Entweder über GetParameterPlaceholder .
    • Oder fragen Sie die DbMetaDataColumnNames.ParameterMarkerFormat Wert enthalten in das Schema für Ihre Verbindung . Sie sollten in der Lage sein, Ihren Platzhalter zu erstellen, indem Sie diese Zeichenkette als Formatzeichenkette verwenden und den vorherigen Parameternamen als Eingabe verwenden (was bedeutet, dass die Formatzeichenkette "{0}" für Sql Server und ":{0}" für Oracle) :

      // DbConnection connection;
      // string parameterName
      DataRow schema=connection.GetSchema(DbMetaDataCollectionNames.DataSourceInformation).Rows[0];
      string placeholder=string.Format(
          CultureInfo.InvariantCulture,
          (string)schema[DbMetaDataColumnNames.ParameterMarkerFormat],
          name.Substring(0, Math.Min(parameterName.Length, (int)schema[DbMetaDataColumnNames.ParameterNameMaxLength]))
      );

Dies wurde mit Sql Server, Access, Sqlite und Oracle getestet (aber beachten Sie, dass es nicht überraschend ist, dies wird mit ODP .NET nicht funktionieren ...).

0voto

JP Alioto Punkte 44283

Sie könnten einen leichten Leistungsabfall in Kauf nehmen und die System.Data.OleDb Klassen. Auf diese Weise könnten Sie unabhängig von der Datenbank denselben Code verwenden. Oder Sie könnten ein Inversion-of-Control-Framework verwenden wie Einigkeit . Sie könnten dann verlangen, dass Ihre Datenzugriffsklasse mit der entsprechenden Fabrik für die Datenbank, Parameter usw. injiziert wird, die der Aufrufer zu verwenden wünscht.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X