IDbConnection异常

时间:2009-07-17 17:18:43

标签: c# ado.net

我有一个用于Sql或Oracle连接的IDbConnection。我没有问题打开它然后通过连接读取数据或保存数据。但是,当作业完成后,我尝试关闭连接。然后我得到一个例外:“内部.Net Framework数据提供程序错误1”。

以下是一些关闭连接的代码:

if (conn != null) // conn is IDbConnectin
{
  if (conn.State == System.Data.ConnectionState.Open)
  {
    conn.Close(); // bung! exception
  }
  conn.Dispose();
}
conn = null;

在安全关闭连接之前我还应该检查一下吗?

2 个答案:

答案 0 :(得分:2)

我知道它听起来可能不会直接解决您的问题,但IDbConnection是IDisposable,因此请在using {}块中包装使用它的代码。

为什么?

您可能知道在using {}块结束时,会调用Dispose()。并且,在IDbConnection的每个实例中,调用Dispose()将间接调用Close()。但是使用using可以防止你完全遇到这个问题,你会得到额外的好处 - 使用using,你被迫保持创造,开启,关闭和处置连接在同一上下文中

我发现人们遇到问题的大多数问题是他们使用Finalizer或单独的线程来处理他们的连接对象。对我来说,还有一种更大的气味,他们将一次性物品保持活力一段时间,可能会分享同一类别的多个成员之间的联系。

换句话说,当你传递连接对象时,你可能会想写这样的东西:

class AccountService {
   private IDbConnection conn;
   internal AccountService(IDbConnection connection) {
     this.conn = connection;
   }

   public Account GetAccount(String id) {
     IDbCommand command = conn.CreateCommand();
     conn.Open;
     Account a = Account.FromReader(command.Execute(Strings.AccountSelect(id)));
     conn.Close;  // I remembered to call Close here
     return a;
   }

   // ... other methods where I Open() and Close() conn

   // hopefully not necessary since I've been careful to call .Close(), but just in case I forgot or an exception occured
   ~AccountService() { 
     if (conn != null) 
     {
       if (conn.State == System.Data.ConnectionState.Open)
       {
         conn.Close(); 
       }
       conn.Dispose();
     }
     conn = null;
   }
}

如果您使用过 using,则根本不需要考虑使用Finalizer:

// IDbFactory is custom, and used to retrieve a Connection for a given Database
interface IDbFactory {
    IDbConnection Connection { get; }
}

class AccountService {
  private IDbFactory dbFactory; 
  internal AccountService(IDbFactory factory) { 
    this.dbFactory = factory;
  }

  public Account GetAccount(String id) {
    using (IDbConnection connection = dbFactory.Connection) { 
      using (command = connection.GetCommand()) {
        connection.Open();
        return Account.FromReader(command.Execute(Strings.AccountSelect(id)));
      } 
    } // via using, Close and Dispose are automatically called
  }

  // I don't need a finalizer, because there's nothing to close / clean up

}

using规则有例外,特别是如果一次性物品的构造很昂贵,但是100次中有99次,如果你没有使用using,那就有气味。 / p>

答案 1 :(得分:1)

我认为你在其他线程或Finilize方法中调用close方法。不要在类的Finalize方法中对Connection,DataReader或任何其他托管对象调用Close或Dispose。在终结器中,您应该只释放您的类直接拥有的非托管资源。如果您的类不拥有任何非托管资源,请不要在类定义中包含Finalize方法。见here