【问题标题】:Idiom for using SqlDataReader as a resource使用 SqlDataReader 作为资源的习惯用法
【发布时间】:2009-06-30 11:07:32
【问题描述】:

this 问题之后,我发现自己一遍又一遍地编写以下代码:

SqlCommand command = new SqlCommand();
// Code to initialize command with what we want to do
using (SqlConnection connection = openConnection())
{
    command.Connection = connection;
    using (SqlDataReader dataReader = thisCommand.ExecuteReader())
    {
        while (dataReader.Read())
        {
            // Do stuff with results
        }
    }
}

不得不嵌套两个 using 语句是相当乏味的。有没有办法告诉 SqlDataReader 它拥有命令,并告诉命令它拥有连接?

如果有办法做到这一点,那么我可以编写一个可以像这样调用的辅助方法:

// buildAndExecuteCommand opens the connection, initializes the command
// with the connection and returns the SqlDataReader object. Dispose of the
// SqlDataReader to dispose of all resources that were acquired
using(SqlDataReader reader = buildAndExecuteCommand(...))
{
    // Do stuff with reader
}

还是我必须硬着头皮在 SqlDataReader 上编写自己的包装器?

【问题讨论】:

  • 其实,上面的SqlCommand也应该在using语句中,所以你会有3个嵌套语句。

标签: c# .net sql sql-server


【解决方案1】:

有一件事是编写一个为您处理的方法,用每个结果回调一个委托。例如:

using (SqlConnection connection = openConnection())
{
    command.Connection = connection;
    ExecuteReaderWithCommand(command, reader =>
    {
        // Do stuff with the result here.
    });
}

那么 ExecuteReaderWithCommand 会是这样的:

public static void ExecuteReaderWithCommand(SqlCommand command,
    Action<SqlDataReader> action)
{
    using (SqlDataReader dataReader = thisCommand.ExecuteReader())
    {
        while (reader.Read())
        {
            action(reader);
        }
    }
}

如果您愿意,可以将其作为SqlCommand 的扩展方法。哎呀,如果你愿意,你也可以去城里让它为你打开连接……你越能抽象出“打开/使用/关闭”的概念,越好。

【讨论】:

  • +1,lambda 是最干净的。我也在想同样的事情,但像往常一样,斯基特先生很快就抽签了:-)
  • 我同意“你越能抽象出“打开/使用/关闭”的概念——这就是 DAAB 在某种程度上所做的。
  • 是的......虽然使用.NET 2.0,但委托语法最终变得非常笨拙。 叹息
【解决方案2】:

你可以这样写,并告诉dataReader在使用后关闭连接:

SqlCommand command = new SqlCommand();
command.Connection = openConnection();
using (SqlDataReader dataReader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
    while (dataReader.Read())
    {
        // Do stuff with results
    }
}

但是最好显式关闭连接,因为在打开连接和 ExecuteReader 之间可能会发生异常。

【讨论】:

    【解决方案3】:

    您必须自己构建包装器。或者如果可以的话,你可以使用 ORM。

    【讨论】:

      【解决方案4】:

      为什么不看看Enterprise Library DAAB

      这是来自documentation 的代码示例,已针对您的场景进行了调整:

      Database db = DatabaseFactory.CreateDatabase();
      
      using (IDataReader reader = db.ExecuteReader(CommandType.Text, "SQL here..." ))
      {
         while (reader.Read())
          {
              action(reader);
          }
      }
      

      【讨论】:

      • 因为 ADO.NET 适合大多数需求,而且通常没有必要在 [还] 另一个库中。
      • @Arbiter。我从来没有说过使用,我说看看。它解决了这个问题。真正由保罗来决定是否拥有“另一个库”是一个问题。 DAAB 的设计目标之一是防止开发人员重复编写相同的代码。
      • 同意,决定权在作者 :)
      【解决方案5】:

      使用诸如 Action 之类的委托当然是一种选择,但自 .NET 1.0 以来,我使用了一组类似于下面的重载。调用者使用 using 块来处理返回的读取器,而读取器又会处理连接。

      public IDataReader ExecuteReader(string commandText, CommandType commandType, 
                                            IDbDataParameter[] parameters)
      {
          IDbConnection connection = CreateConnection();
          try
          {
              IDbCommand command = CreateCommand(commandText, connection);
              command.CommandType = commandType;
              AppendParameters(command, parameters);
              connection.Open();
              return command.ExecuteReader(CommandBehavior.CloseConnection);
          }
          catch
          {
              connection.Close();
              throw;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-06-08
        • 2012-09-15
        • 2010-10-05
        • 2014-05-08
        • 1970-01-01
        • 2012-11-12
        • 1970-01-01
        相关资源
        最近更新 更多