简体   繁体   English

在C#中调用多个“SQL DataReader”的正确方法是什么?

[英]What is the proper way of calling multiple “SQL DataReader”s in C#?

I call ExecuteReader(); 我调用ExecuteReader(); to get data, then i need to get another data with another query. 要获取数据,那么我需要使用另一个查询获取另一个数据。 My structure's been always like this : 我的结构一直都是这样的:

class SomeClass
{
    public static void Main(String[] args)
    {
        SqlConnection sqlConn = new SqlConnection();
        sqlConn.ConnectionString = "some connection string" 

        SqlCommand SQLCmd = new SqlCommand();
        SQLCmd.CommandText = "some query";
        SQLCmd.Connection = sqlConn;
        sqlConn.Open();

        sqlReader = SQLCmd.ExecuteReader();

        while (sqlReader.Read())
        {
            //some stuff here
        }

        sqlReader.Dispose();
        sqlReader.Close();
        sqlConn.Close();

        SQLCmd.CommandText = "another query";
        sqlConn.Open();
        sqlReader = SQLCmd.ExecuteReader();

        while (sqlReader.Read())
        {
            //some other stuff here
        }

        sqlReader.Dispose();
        sqlReader.Close();
        sqlConn.Close();
    }
}

They share the same connection string. 它们共享相同的连接字符串。 What else can they share ? 他们还能分享什么? Can they share same sqlConn.Open(); 他们可以共享相同的sqlConn.Open(); ? What is the proper way of resource allocating and avoiding errors ? 什么是资源分配和避免错误的正确方法?

BTW it works as it is. BTW它的工作原理。 Thanks in advance. 提前致谢。

This is how I would write all of that: 这就是我写所有这些的方式:

class SomeClass
{
 public static void Main(String[] args)
 {
  using (SqlConnection sqlConn = new SqlConnection("some connection string"))
  {
   sqlConn.Open();

   using (SqlCommand comm = new SqlCommand("some query", conn))
   using (var sqlReader = comm.ExecuteReader())
   {
    while (sqlReader.Read())
    {
     //some stuff here
    }
   }

   using (SqlCommand comm = new SqlCommand("some query", conn))
   using (var sqlReader = comm.ExecuteReader())
   {
    while (sqlReader.Read())
    {
     //some other stuff here
    }
   }
  }
 }
}

The using statement handles disposing of items when the block is finished. using语句处理块完成时处理项目。 As for sharing stuff, you could leave the connection open across the commands. 至于共享内容,您可以在命令之间保持连接打开。

The most important thing to dispose out of all of that would be the connection, but I tend towards honouring a using statement if an item is IDisposable regardless of what it actually does in the background (which is liable to change as it's an implementation detail). 处理所有这一切的最重要的事情就是连接,但是如果一个项目是IDisposable而不管它在后台实际做了什么(由于它是一个实现细节,它可能会改变),我倾向于尊重using声明。 。

Don't forget, there is also Multiple Active Result Sets (as demonstrated in this answer) from a single command and a single reader, where you advance the reader onto the next result set. 不要忘记,单个命令和单个阅读器中还有多个活动结果集(如本答案中所示) ,您可以将阅读器推进到下一个结果集。


My slightly more flippant answer to how I might write all of that would be: 对于我如何编写所有这些内容,我略微轻率一点的答案是:

  return connection.Query<T>(procedureName, param, commandType: CommandType.StoredProcedure); 

Using Dapper ;-) 使用Dapper ;-)

As alluded to in my comment - if possible, combine the two queries into one and then (if it still produces multiple result sets), use NextResult to move on. 正如我的评论中提到的那样 - 如果可能的话,将两个查询合并为一个然后(如果它仍然产生多个结果集),使用NextResult继续前进。

Stealing Adam's structure , but with that change: 窃取亚当的结构 ,但随着这种变化:

class SomeClass
{
 public static void Main(String[] args)
 {
  using (SqlConnection sqlConn = new SqlConnection("some connection string"))
  {
   sqlConn.Open();

   using (SqlCommand comm = new SqlCommand("some query; some other query;", conn))
   using (var sqlReader = comm.ExecuteReader())
   {
    while (sqlReader.Read())
    {
     //some stuff here
    }
    if(sqlReader.NextResult())
    {
      while (sqlReader.Read())
      {
       //some other stuff here
      }
     }
    }
  }
 }
}

The proper way is to wrap SqlConnection s and SqlCommand s in using -statements. 正确的方法是using -statements包装SqlConnectionSqlCommand This will force Dispose to be invoked on the objects when the using block is left, even if an Exception is thrown. 这将强制在使用块时保留对象的Dispose ,即使抛出异常也是如此。 (This is not the case with your current code.) (当前代码不是这种情况。)

Something in the line of 有点像

using(var cnn = new SqlConnection("connectionstring")){
    cnn.Open();
    using(var cmd = new SqlCommand("SELECT 1")){
       var reader = cmd.ExecuteReader();
       while(reader.Read()) { /* doStuff */ }
    }
}

Regardless of the approach Close / Dispose will not actually close the connection since connection setup is very expensive. 无论何种方法, Close / Dispose都不会实际关闭连接,因为连接设置非常昂贵。 It will just return the connection to a connection pool and allow other commands/readers to use it. 它只会将连接返回到连接池,并允许其他命令/读者使用它。

To manage resource you can use using like as shown under ... 为了管理资源,您可以使用using像在如图所示...

 SQLCmd.CommandText = "some query";
 SQLCmd.Connection = sqlConn;
 sqlConn.Open();

//using will dispose reader automatically.
 using(sqlReader = SQLCmd.ExecuteReader())
{
   while (sqlReader.Read())
    {
    //some stuff here
    }
}
 //sqlReader.Dispose();
 //sqlReader.Close();
 //sqlConn.Close();

 SQLCmd.CommandText = "another query";
//no need to open connection again.
// sqlConn.Open();
// sqlReader = SQLCmd.ExecuteReader();

 using(sqlReader = SQLCmd.ExecuteReader())
{
   while (sqlReader.Read())
    {
    //some stuff here
    }
}
 //sqlReader.Dispose();
 //sqlReader.Close();
 //sqlConn.Close();

you can use using only for those classes which have implemented IDispose interface. 您可以使用using仅适用于已经实现了这些类IDispose接口。 in your example you can use SqlConnection and SqlCommand also with using code block. 在您的示例中,您还可以使用SqlConnectionSqlCommand使用代码块。

Use 'using', you don't need to manually close and dispose. 使用'使用',您无需手动关闭和处理。

using (SqlConnection connection = new SqlConnection(connectionString)) 
{    
     connection.Open();
     SqlCommand command = new SqlCommand("spTest", connection);
     command.CommandType = CommandType.StoredProcedure;
     command.Parameters.Add(new SqlParameter("@employeeid", employeeID));
     command.CommandTimeout = 5;

     command.ExecuteNonQuery();
}

Open a new connection every time you need it is a best practices. 每次需要时打开一个新连接是最佳实践。 ADO.net use connection pool to menage connection. ADO.net使用连接池来进行连接。 http://msdn.microsoft.com/it-it/library/8xx3tyca(v=vs.110).aspx http://msdn.microsoft.com/it-it/library/8xx3tyca(v=vs.110).aspx

Dont forget your try catch statements though :) 不要忘记你的try catch语句:)

class SomeClass
{
 public static void Main(String[] args)
 {
  using (SqlConnection sqlConn = new SqlConnection("some connection string"))
  {
   try{
   sqlConn.Open();

   using (SqlCommand comm = new SqlCommand("some query", conn))
   using (var sqlReader = comm.ExecuteReader())
   {
    while (sqlReader.Read())
    {
     //some stuff here
    }
   }

   using (SqlCommand comm = new SqlCommand("some query", conn))
   using (var sqlReader = comm.ExecuteReader())
   {
    while (sqlReader.Read())
    {
     //some other stuff here
    }
   }
   }
   catch()
{
// Do exception catching here or rollbacktransaction if your using begin transact
}
finally
{
sqlConn.Close();
}
  }
 }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM