2012-06-20 54 views
4

我必須使用ODBC連接調用C#(.Net 2.0)中的存儲過程,有時使用SQLClient調用。我將來也可以與Oracle溝通。如何在C#中使用通用數據庫連接調用存儲過程?

我的存儲過程有輸入/輸出參數和返回值。

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 
} 

感謝您的時間。

Regards, Thibaut。

+0

這個問題有更好的示例代碼,其中99%的答案在那裏討論IDbConnection ... :) –

回答

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命令和參數支持之上創建一個抽象層,但我認爲這裏並不是必須的。這不像你不寫一個完整的數據提供者。

+0

感謝您的回答。 我不得不推遲這個項目,因爲我們不再需要ODBC連接。 我會在接下來的幾周嘗試使用IDbCommand的包裝器更新我們的API,正如你所建議的那樣。我只需要時間回顧一下這個話題。 再次感謝:) –

相關問題