我应该在哪里创建我的DbCommand实例?

时间:2009-08-09 19:33:35

标签: .net sqlite ado.net system.data.sqlite system.data

我似乎有两个选择:

  1. 让我的班级实施IDisposable。将我的DbCommand个实例创建为private readonly个字段,并在构造函数中添加它们使用的参数。每当我想写入数据库时​​,绑定到这些参数(重用相同的命令实例),设置ConnectionTransaction属性,然后调用ExecuteNonQuery。在Dispose方法中,在每个字段上调用Dispose
  2. 每次我想写入数据库时​​,围绕命令的使用编写using(var cmd = new DbCommand("...", connection, transaction)),并在调用ExecuteNonQuery之前每次添加参数并绑定它们。我假设我不需要为每个查询创建一个新命令,每次打开数据库时都只需要一个新命令(对吗?)。
  3. 这些都看起来有点不雅,可能不正确。

    对于#1,我的用户觉得我这个类现在IDisposable只是因为我使用了一些DbCommand(这应该是他们不关心的实现细节)关于)。我也有点怀疑保留一个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
    }
    

3 个答案:

答案 0 :(得分:2)

没有一种“正确的方法”来处理数据库对象的生命周期。这完全取决于您的应用需求。

我个人的偏好是让代码尽可能简单。我倾向于根据需要重新创建Command和Parameter对象。这使我的功能尽可能自包含。它大大简化了我必须做的任何重新分解。

如果您担心重新创建对象的性能损失,您应该加载一个分析器并查看瓶颈的位置。在我构建的应用程序中,我发现创建DbCommand对象所花费的时间与执行查询所花费的时间相比是无关紧要的,因为它并没有真正影响我的应用程序性能。

答案 1 :(得分:2)

Domenic, 处置SQLiteCommand只是通知其活动读取器处理它的读取器并将参数和连接引用设置为null。

只要您正确处理已执行的阅读器并关闭/处置连接,您就不会因为缓存命令而面临资源泄漏的风险。

因此,重用缓存命令并简单地为参数赋值是迄今为止最有效的实现。

.Prepare()是SQLiteCommand中的noop所以没有任何好处。

答案 2 :(得分:0)

我已经找到了sqlserver,如果我们重用具有相同连接的命令,它会更快。我计划测试不同的连接和交易,但它们看起来更快。