簡體   English   中英

將DB Connection對象傳遞給方法

[英]passing DB Connection object to methods

想知道是否建議傳遞數據庫連接對象(到其他模塊)或讓方法(在其他模塊中)負責設置它。 我傾向於讓方法設置它,以便在使用之前不必檢查連接的狀態,只是讓調用者將任何所需的數據傳遞給設置連接所需的調用方法。

我個人喜歡使用嚴格的連接; 打開它們,使用它們並關閉它們(在“使用”塊中,所有都在本地方法中)。 在大多數情況下,連接池將處理重新使用連接,因此這種方法沒有實際開銷。

在路過曾經是這樣,你可以通過周圍的交易連接的主要優勢; 但是, TransactionScope是一種在方法之間共享TransactionScope的簡單方法。

由於這些類是特定於實現的,因此我會編寫每個類來打開它自己的本機事務。 否則,您可以使用ado.net工廠方法從配置文件(提供程序名稱)創建相應的類型。

就個人而言,我喜歡使用SetData和GetData在Thread Local Storage之上存儲我當前打開的連接和事務的堆棧。 我定義了一個類來管理我與數據庫的連接,並允許它使用dispose模式。 這節省了我傳遞連接和事務的需要,這是我認為使代碼混亂和復雜化的東西。

我強烈建議不要在每次需要數據時都要打開連接方法。 這將導致一個非常糟糕的情況,即整個應用程序都難以管理事務,並且打開和關閉了太多連接(我知道連接池,從池中查找連接的成本仍然比它更昂貴重用一個對象)

所以我最終得到了這些內容(完全未經測試):

class DatabaseContext : IDisposable {

    List<DatabaseContext> currentContexts;
    SqlConnection connection;
    bool first = false; 

    DatabaseContext (List<DatabaseContext> contexts)
    {
        currentContexts = contexts;
        if (contexts.Count == 0)
        {
            connection = new SqlConnection(); // fill in info 
            connection.Open();
            first = true;
        }
        else
        {
            connection = contexts.First().connection;
        }

        contexts.Add(this);
    }

   static List<DatabaseContext> DatabaseContexts {
        get
        {
            var contexts = CallContext.GetData("contexts") as List<DatabaseContext>;
            if (contexts == null)
            {
                contexts = new List<DatabaseContext>();
                CallContext.SetData("contexts", contexts);
            }
            return contexts;
        }
    }

    public static DatabaseContext GetOpenConnection() 
    {
        return new DatabaseContext(DatabaseContexts);
    }


    public SqlCommand CreateCommand(string sql)
    {
        var cmd = new SqlCommand(sql);
        cmd.Connection = connection;
        return cmd;
    }

    public void Dispose()
    {
        if (first)
        {
            connection.Close();
        }
        currentContexts.Remove(this);
    }
}



void Test()
{
    // connection is opened here
    using (var ctx = DatabaseContext.GetOpenConnection())
    {
        using (var cmd = ctx.CreateCommand("select 1"))
        {
            cmd.ExecuteNonQuery(); 
        }

        Test2(); 
    }
    // closed after dispose
}

void Test2()
{
    // reuse existing connection 
    using (var ctx = DatabaseContext.GetOpenConnection())
    {
        using (var cmd = ctx.CreateCommand("select 2"))
        {
            cmd.ExecuteNonQuery();
        }
    }
    // leaves connection open
}

出於自動化測試的目的,通常更容易將其傳入。這稱為依賴注入

當您需要編寫測試時,您可以創建一個模擬數據庫連接對象並傳遞它而不是真實的。 這樣,您的自動化測試將不依賴於每次都需要重新填充數據的實際數據庫。

我個人努力盡可能地集中我的數據訪問,但是,如果不可能的話,我總是在其他類中打開一個新連接,因為我發現在傳遞實際連接時有太多其他東西可能會妨礙我賓語。

建立連接可能很昂貴,並可能增加往返。 因此,再次,可能,更好的設計是傳遞連接對象。

我可能會說,因為如果你是一個Microsoft ADO應用程序,你可能正在使用連接池....

以下是對此問題的更深入了解。 我有一個管理數據庫連接的類,並有2個實現接口的類。 其中一個類用於SQL,另一個用於OLAP。 管理器是知道要使用哪個連接的管理器,因此它可以傳遞與該類型的確切連接,或者類型可以創建自己的連接。

您可以毫無問題地傳遞連接對象(例如Microsoft Enterprise Library允許通過連接傳遞靜態方法調用),或者您可以在外部管理它直到您的設計,沒有直接的技術權衡。

如果您的解決方案將被移植到其他數據庫,請注意不要傳遞特定連接的可移植性(意味着不要傳遞您計划與其他數據庫一起使用的SqlConnection)

我建議您區分連接對象及其狀態(打開,關閉)。

您可以使用單個方法(或屬性)從web.config讀取連接字符串。 每次使用相同版本的連接字符串可確保您從連接池中受益。

需要打開連接時調用該方法。 在最后一刻,在設置所有SqlCommand屬性后,打開連接,使用它,然后關閉它。 在C#中,您可以使用using語句來確保連接已關閉。 如果沒有,請確保在finally塊中關閉連接。

我會使用web.config

<configuration>
    <connectionStrings>
        <add name="conn1" providerName="System.Data.SqlClient" connectionString="string here" />
        <add name="conn2" providerName="System.Data.SqlClient" connectionString="string here" />
    </connectionStrings>
</configuration>

然后,您可以從應用程序的任何位置引用它

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM