2009-08-09 82 views
1

我似乎有兩個選擇:我應該在哪裏創建我的DbCommand實例?

  1. 讓我的類實現IDisposable。將我的DbCommand實例創建爲private readonly字段,並在構造函數中添加它們使用的參數。每當我想寫入數據庫時​​,綁定到這些參數(重用相同的命令實例),設置ConnectionTransaction屬性,然後調用ExecuteNonQuery。在Dispose方法中,在這些字段的每一個上調用Dispose
  2. 每次我想要寫入數據庫時​​,請在命令的使用周圍寫入using(var cmd = new DbCommand("...", connection, transaction)),然後在調用ExecuteNonQuery之前每次添加參數並綁定它們。我假設每個查詢都不需要新的命令,每次打開數據庫時都需要一個新的命令(對吧?)。

這兩個都顯得有些不雅,可能不正確。

對於#1,這對我的用戶來說很煩,因爲我已經使用了幾個(這應該是他們不關心的實現細節),所以本課程現在是IDisposable。我也有點懷疑保持一個DbCommand實例可能會無意中鎖定數據庫或其他東西?

對於#2,感覺就像我每次要寫入數據庫時​​都要做很多工作(就.NET對象而言),特別是使用參數添加。我似乎每次都創建一個相同的對象,這只是一種不好的練習。

僅供參考,這裏是我當前的代碼,使用#1:

using System; 
using System.Net; 
using System.Data.SQLite; 

public class Class1 : IDisposable 
{ 
    private readonly SQLiteCommand updateCookie = new SQLiteCommand("UPDATE moz_cookies SET value = @value, expiry = @expiry, isSecure = @isSecure, isHttpOnly = @isHttpOnly WHERE name = @name AND host = @host AND path = @path"); 
    public Class1() 
    { 
     this.updateCookie.Parameters.AddRange(new[] 
          { 
           new SQLiteParameter("@name"), 
           new SQLiteParameter("@value"), 
           new SQLiteParameter("@host"), 
           new SQLiteParameter("@path"), 
           new SQLiteParameter("@expiry"), 
           new SQLiteParameter("@isSecure"), 
           new SQLiteParameter("@isHttpOnly") 
          }); 
    } 

    private static void BindDbCommandToMozillaCookie(DbCommand command, Cookie cookie) 
    { 
     long expiresSeconds = (long)cookie.Expires.TotalSeconds; 

     command.Parameters["@name"].Value = cookie.Name; 
     command.Parameters["@value"].Value = cookie.Value; 
     command.Parameters["@host"].Value = cookie.Domain; 
     command.Parameters["@path"].Value = cookie.Path; 
     command.Parameters["@expiry"].Value = expiresSeconds; 
     command.Parameters["@isSecure"].Value = cookie.Secure; 
     command.Parameters["@isHttpOnly"].Value = cookie.HttpOnly; 
    } 

    public void WriteCurrentCookiesToMozillaBasedBrowserSqlite(string databaseFilename) 
    { 
     using (SQLiteConnection connection = new SQLiteConnection("Data Source=" + databaseFilename)) 
     { 
      connection.Open(); 
      using (SQLiteTransaction transaction = connection.BeginTransaction()) 
      { 
       this.updateCookie.Connection = connection; 
       this.updateCookie.Transaction = transaction; 

       foreach (Cookie cookie in SomeOtherClass.GetCookieArray()) 
       { 
        Class1.BindDbCommandToMozillaCookie(this.updateCookie, cookie); 
        this.updateCookie.ExecuteNonQuery(); 
       } 

       transaction.Commit(); 
      } 
     } 
    } 

    #region IDisposable implementation 
    protected virtual void Dispose(bool disposing) 
    { 
     if (!this.disposed && disposing) 
     { 
      this.updateCookie.Dispose(); 
     } 
     this.disposed = true; 
    } 
    public void Dispose() 
    { 
     this.Dispose(true); 
     GC.SuppressFinalize(this); 
    } 
    ~Class1() 
    { 
     this.Dispose(false); 
    } 

    private bool disposed; 
    #endregion 
} 

回答

2

Domenic, 處置一個SQLiteCommand只是表示它的活動閱讀器將它的閱讀器處理掉,並將參數和連接引用設置爲null。

只要您正確處理執行的閱讀器並關閉/處理連接,就不會因緩存命令而導致資源泄漏。

因此,重用緩存命令並簡單地爲參數賦值是迄今爲止最有效的實現。

。Prepare()在SQLiteCommand中是一個noop,所以在那裏沒有任何好處。

+0

所以我不需要'Dispose()'的命令本身,只是連接和事務?所以例如我的示例代碼可以在沒有所有'IDisposable'的情況下工作? – Domenic 2010-04-25 19:48:02

+0

@domenic是的,我會說你的課並不表示需要一次性使用,而且絕對不需要析構函數。你可以刪除所有的IDisposable,因爲你的類基本上是一個命令包裝器。 'WriteCurrentCookiesToMozillaBasedBrowserSqlite'完成你需要做的所有清理工作。您可以重新使用infinitum類的同一個實例。 – 2010-04-25 19:56:27

2

沒有單一的「正確的方式」來處理你的數據庫對象的生命週期。這完全取決於您的應用需求。

我個人的偏好是保持代碼儘可能簡單。我傾向於根據需要重新創建Command和Parameter對象。這可以讓我的功能儘可能地包含自我。它大大簡化了我不得不做的任何重新分解。

如果您擔心重新創建對象的性能受到影響,您應該加載一個探查器並查看瓶頸位置。在我創建的應用程序中,我發現創建DbCommand對象的時間與執行查詢所花費的時間相比是非常無關緊要的,它並不真正影響我的應用程序性能。

+0

我不擔心重新創建它們的性能;我很關心代碼在我這樣做時的感受。這似乎很奇怪,你會創建一個對象,添加一些參數,然後綁定到這些參數,每當你想運行數據庫查詢。但是,也許這是要走的路,畢竟...... – Domenic 2009-08-12 09:16:43

0

我發現與sqlserver,如果我們重複使用相同的連接命令,其速度更快。我打算測試不同的連接和交易,但它們似乎更快。