C# Oracle DataReader正在关闭连接,然后才能读取数据

C# Oracle DataReader正在关闭连接,然后才能读取数据,c#,oracle,wcf,C#,Oracle,Wcf,我有一个返回OracleDataReader对象的函数。这是: public OracleDataReader executeCommand(string query) { using (conn) { conn.ConnectionString = connectionString; conn.Open(); OracleCommand cmd = conn.CreateComma

我有一个返回
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;
        }
    }
当我试图通过另一个类中的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;
    }
异常
当读卡器关闭时,获取序号的尝试无效


有什么问题?我没有关闭读卡器?

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

using (conn)
{
   conn.ConnectionString = connectionString;
   conn.Open();
   ...
   return reader;
} --> Disposes of connection, which closes it, so reader can't read.
一个选项是使用块将连接放置在
中,而不是将连接放置在
块中,如果要将
读取器
传递到拥有连接的方法的控制之外,可以指定
CommandBehavior.CloseConnection
在读取器关闭时关闭连接,但不要关闭或处理连接,即

OracleDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
return reader;
在我看来,一种更安全的模式(如果您使用
foreach
),而不将资源处置的责任留给调用者,也不将读取器传递到函数之外,将使用
产生返回
,尽管这将改变代码的工作方式:

  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());
            }
          }
        }
     }
  }
public IEnumerable RetrievePeople()
{
使用(var conn=新的OracleConnection(connString))
{
conn.Open();
使用(var cmd=conn.CreateCommand())
{
cmd.CommandText=查询;
使用(var reader=cmd.ExecuteReader())
{
while(reader.Read())
{
回报新人(
转换.ToInt32(读卡器[“id”]),
读取器[“first_name”]。ToString(),
读卡器[“姓氏].ToString());
}
}
}
}
}

通过这种方式,您不需要传递读取器,但是,在迭代器完成之前,连接将保持打开状态。这样做的好处是保留了
读卡器的惰性评估方法,而无需实际传递读卡器,也无需问
之后谁将清理连接。

一旦退出
using
作用域,您的代码就会关闭连接,因此,任何读取尝试都将失败:

using (conn)
{
   conn.ConnectionString = connectionString;
   conn.Open();
   ...
   return reader;
} --> Disposes of connection, which closes it, so reader can't read.
一个选项是使用
块将连接放置在
中,而不是将连接放置在
块中,如果要将
读取器
传递到拥有连接的方法的控制之外,可以指定
CommandBehavior.CloseConnection
在读取器关闭时关闭连接,但不要关闭或处理连接,即

OracleDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
return reader;
在我看来,一种更安全的模式(如果您使用
foreach
),而不将资源处置的责任留给调用者,也不将读取器传递到函数之外,将使用
产生返回
,尽管这将改变代码的工作方式:

  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());
            }
          }
        }
     }
  }
public IEnumerable RetrievePeople()
{
使用(var conn=新的OracleConnection(connString))
{
conn.Open();
使用(var cmd=conn.CreateCommand())
{
cmd.CommandText=查询;
使用(var reader=cmd.ExecuteReader())
{
while(reader.Read())
{
回报新人(
转换.ToInt32(读卡器[“id”]),
读取器[“first_name”]。ToString(),
读卡器[“姓氏].ToString());
}
}
}
}
}

通过这种方式,您不需要传递读取器,但是,在迭代器完成之前,连接将保持打开状态。这样做的好处是保留了
读取器
的惰性评估方法,而不实际传递读取器,如果没有
之后谁来清理连接的问题。

你处理了连接。你处理了连接。不要忘记
OracleDataReader
和OracleCommand`implement
IDisposable
非常感谢Stuart,但是我有一个问题。这是一个很好的设计,使得DB操作类中的Person操作更大吗?PS:Person操作会更大。Person可以被视为某种类型的强类型DTO。大多数ORM都鼓励这种交互。您将
人员
数据传递到您的体系结构上的距离取决于您。谢谢Stuart。这非常有帮助。不要忘记
OracleDataReader
和OracleCommand`implement
IDisposable
非常感谢Stuart,但是我有一个问题。这是一个很好的设计,使得DB操作类中的Person操作更大吗?PS:Person操作会更大。Person可以被视为某种类型的强类型DTO。大多数ORM都鼓励这种交互。通过
人员
d提升架构的距离取决于您。谢谢Stuart。这非常有帮助。