简体   繁体   中英

reader.Read() evaluating a boolean to true or false

Lets say I have the following c# code:

private bool MethodName(string inviteId)
{
  var command = new SqlCommand
    {
      CommandText = "SELECT statement goes here",
      Connection = conn
    } ;
  var reader = command.ExecuteReader();
  return reader.Read();
}

Lets assume that the fictitious SQL query returns rows if rows exist that meet the query criteria. If I were to run this code and there was nothing in the database that meets the criteria, the method should evaluate false, correct? In other words, if the query returns an empty result, will it evaluate as false, but if it returns rows it will evaluate as true?

Thanks

You're executing SqlDataReader.Read() , whose return value is documented as such:

true if there are more rows; otherwise false.

Given your query returns 0 rows, it will return false immediately. Your F5 key could have told you this also. ;-)

是的,您是正确的。您还可以使用HasRows属性代替Read方法。

return reader.HasRows;

Your method

private bool MethodName(string inviteId)
{
  var command = new SqlCommand
  {
    CommandText = "SELECT statement goes here",
    Connection = conn
  } ;
  var reader = command.ExecuteReader();
  return reader.Read();
}

While it does return a true/false value indicating whether the sql query retrieve any rows or not, it leaves the data reader, the command and the connection hung.

There are rows waiting to be read on the SqlDataReader.

On exit from your method, the SqlCommand and SqlDataReader go out of scope. They will eventually be garbage collected, but until they do:

  • the connection is locked, since it has an in-flight command execution. That means that nobody else can use it until the SqlCommand and SqlDataReader are Disposed and garbage collected. Which might be a while.

  • Your SQL Server instance has pending reads on the connection's SPID, meaning it has outstanding locks. That will eventually cause blocking in the database, and your DBAs will be grumpy.

SqlConnection and SqlCommand , etc, are all IDisposable . That means you can use with with using to ensure that they are properly disposed of and all resources they hold are released when they go out of scope. Further, SqlConnection is pooled by default, meaning that you should usually open the connection, do your work and immediately close it , thus returning it to the pool for another use.

So...if what you're trying to do is check whether or not a condition exists in the database, do something like this, taking advantage of the above. The code is cleaner and you won't be tearing out your hair trying to figure out why there are seemingly ghost SPIDs floating about your SQL server and blocking other users:

static bool ConditionExists( string someParameterValue )
{
  bool exists ; // our return value

  const string query = @"
    select convert(bit,sign(count(*)))
    from foo t
    where t.someColumn = @p1
    " ;
  string connectionString = GetConnectionString() ;

  using ( SqlConnection connection = new SqlConnection(connectionString) )
  using ( SqlCommand    cmd        = connection.CreateCommand() )
  {
    cmd.CommandText = query ;
    cmd.CommandType = CommandType.Text;
    connection.Open() ;
    exists = (bool) cmd.ExecuteScalar() ;
    connection.Close() ;
  }

  return exists ;
}

Edited to note: using doesn't do garbage collection. Garbage colleciton in C# is non-deterministic : the system decided when the garbage collector runs and how intensive it is. using ensures that IDisposable objects have their Dispose() method invoked when the reference goes out of scope. Unless you explicitly invoke Dispose() when you are done with an object, allowing an IDisposable to release the resources it holds, while Dispose() will eventually be invoked when the object instance is cleaned up by the garbage collector, that may be quite a while...and the held resources, in the meantime, can cause problems for other objects/processes/etc.

While the construct

using ( Widget foo = new Widget() )
{
  DoSomethingUseful() ;
}

is [pretty much] exactly equivalent to the construct

Widget foo ;
try
{
  foo = new Widget() ;
  DoSomethingUseful() ;
}
finally
{
  foo.Dispose() ;
}

(with the exception that using scopes the variable), but why would you do all the extra typing try / finally requires instead of the terse and concise using ?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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