Как вызвать сохраненный процесс с использованием общего подключения к БД в C#?

Я должен вызывать хранимые процедуры в C# (.Net 2.0), иногда используя ODBC-соединение, иногда с помощью SQLClient. В будущем мы могли бы также общаться с Oracle.

Мои хранимые процедуры имеют параметры ввода / вывода и возвращаемое значение.

CREATE PROCEDURE myProc (@MyInputArg varchar(10), @MyOutputArg varchar(20) output) AS (...) return @@ERROR

Моя проблема в том, что я не могу найти способ сохранить команду, которая может быть общей для любого клиента. Я использую объект IDbCommand.

С подключением ODBC я должен определить:

objCmd.CommandText = "? = CALL myProc (?,?)";

В контексте SQLclient:

objCmd.CommandText = "myProc";

Я не очень хочу разбирать мою команду, я уверен, что есть лучший способ иметь общую команду!

Чтобы помочь людям воспроизвести, вы можете найти ниже, как я сделал общее соединение с БД. В моем контексте объект провайдера определяется из файла конфигурации.

// My DB connection string, init is done from a configuration file
string myConnectionStr = "";

// Provider which defined the connection type, init from config file
//object objProvider = new OdbcConnection(); //ODBC
object objProvider = new SqlConnection(); // SQLClient

// My query -- must be adapted switch ODBC or SQLClient -- that's my problem!
//string myQuery = "? = CALL myProc (?,?)"; // ODBC
string myQuery = "myProc"; // SQLClient

// Prepare the connection
using (IDbConnection conn = (IDbConnection)Activator.CreateInstance(typeof(objProvider), myConnectionStr ))
{
    // Command creation
    IDbCommand objCmd = (IDbCommand)Activator.CreateInstance(typeof(objProvider));
    objCmd.Connection = conn;

    // Define the command
    objCmd.CommandType = CommandType.StoredProcedure;
    objCmd.CommandTimeout = 30;
    objCmd.CommandText = myQuery;

    IDbDataParameter param;

    // Return value
    param = (IDbDataParameter)Activator.CreateInstance(typeof(objProvider));
    param.ParameterName = "RETURN_VALUE";
    param.DbType = DbType.Int32;
    param.Direction = ParameterDirection.ReturnValue;
    objCmd.Parameters.Add(param);

    // Param 1 (input)
    param = (IDbDataParameter)Activator.CreateInstance(typeof(objProvider));
    param.ParameterName = "@MyInputArg";
    param.DbType = DbType.AnsiString;
    param.Size = 10;
    param.Direction = ParameterDirection.Input;
    param.Value = "myInputValue";
    objCmd.Parameters.Add(param);

    // Param 2 (output)
    param = (IDbDataParameter)Activator.CreateInstance(typeof(objProvider));
    param.ParameterName = "@MyOutputArg";
    param.DbType = DbType.AnsiString;
    param.Size = 20;
    param.Direction = ParameterDirection.Output;
    objCmd.Parameters.Add(param);

    // Open and execute the command
    objCmd.Connection.Open();
    objCmd.ExecuteReader(CommandBehavior.SingleResult);
    (...) // Treatment
}

Спасибо за ваше время.

С уважением, Тибо.

1 ответ

Решение

Вы можете создать обертку вокруг IDbCommand и реализаций (но только если вы хотите:)).

//Note the IDisposable interface
public class MultiSqlCommand : IDisposable
{
  //DbConnectionType  is a custom enum
  public MultiSqlCommand(DbConnectionType connType, DbConnection conn)
  {
    //initialize members
    ...
    switch(connType) 
    {
      case ADO:
        _cmd = new SqlCommand(_connection);
        break;
      case ODBC:
        ...
    }
  }

  //As param name you pass the undecorated parameter name (no @, ?, etc.)
  public void AddParameter(string strippedName, object value) 
  {
    //this should be an internal function which gives you an SqlParameter formatted for your specific DbConnectionType
    object parameter = GetSqlParam(strippedName, value);
    _cmd.Parameters.Add(object);
  }
}

После добавления параметров ваша команда готова к выполнению. Вы можете либо выставить его через свойство и выполнить за пределами этого класса, либо расширить API и добавить несколько методов для его выполнения и получения результатов. Все, что вы найдете удобным.

Примечание. В вашей реализации IDisposable вы должны располагать экземпляром IDbCommand (если не ноль). Это очень важно, иначе вы потеряете память.

Если предложение не ясно, то дайте мне знать, и я постараюсь заполнить его более подробной информацией. Решение простое, я бы сказал. Вы можете пойти дальше и создать слой абстракции поверх всей поддержки команд и параметров ADO.NET, но я не думаю, что здесь действительно нужно. Это не значит, что вы не пишете весь провайдер данных.

Другие вопросы по тегам