在我可以读取数据之前,Oracle DataReader关闭连接

时间:2014-01-31 07:17:23

标签: c# oracle wcf

我有一个返回OracleDataReader对象的函数。这是:

 public OracleDataReader executeCommand(string query)
    {
        using (conn)
        {
            conn.ConnectionString = connectionString;
            conn.Open();
            OracleCommand cmd = conn.CreateCommand();
            cmd.CommandText = query;
            OracleDataReader reader = cmd.ExecuteReader();
            return reader;
        }
    }

当我试图在另一个类中使用阅读器获取数据时,我得到一个例外:

public Person GetPersonById(int id)
    {
        OracleDBOp db = new OracleDBOp();
        String query = "select * from test_person where id=" + id;
        OracleDataReader reader = db.executeCommand(query);
        Person person = null;
        person = new Person(Convert.ToInt32(reader["id"]),reader["first_name"].ToString(),reader["last_name"].ToString());
        return person;
    }
  

异常
  读取器关闭时对GetOrdinal的尝试无效。

有什么问题?我不是在关闭读者吗?

1 个答案:

答案 0 :(得分:4)

您的代码会在退出using范围后立即关闭连接,因此任何读取尝试都将失败:

using (conn)
{
   conn.ConnectionString = connectionString;
   conn.Open();
   ...
   return reader;
} --> Disposes of connection, which closes it, so reader can't read.

一种选择是,不是将连接放在using块中,如果您打算将reader传递给拥有连接的方法的控制之外,您可以指定CommandBehavior.CloseConnection在阅读器关闭时关闭连接,但不要关闭或丢弃连接,即

OracleDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
return reader;

IMO,一种更安全的模式(假设你play nicely with the iterator,例如foreach),而不是将资源处理给调用者,并且不将读者传递给函数,将使用yield return,虽然这将改变您的代码的工作方式:

  public IEnumerable<Person> RetrievePeople()
  {
      using (var conn = new OracleConnection(connString))
      {
        conn.Open();
        using (var cmd = conn.CreateCommand())
        {
          cmd.CommandText = query;
          using (var reader = cmd.ExecuteReader())
          {
            while (reader.Read())
            {
               yield return new new Person(
                 Convert.ToInt32(reader["id"]),
                 reader["first_name"].ToString(),
                 reader["last_name"].ToString());
            }
          }
        }
     }
  }

这样您就不需要通过阅读器了,但是在迭代器完成之前,连接将保持打开状态。这有利于保留reader的惰性评估方法,而不会实际传递读者,并且之后不会出现who is going to clean up连接问题。