How does the sql process behave? - c#

From my C# program, I open the sql connection and do some updates to tables. After that I close the connection. And, If I check under Activity Monitor in Management Studio, New Process is created and even though I closed my sql connection from the program, the process is still there in Activity Monitor. May I know how this process behaves? Do we need to clear these processes explicitly? Thanks.

I think you are using the concept of process incorrectly here.
ADO.NET uses a connection pool. This means that when you call the Open method on a SqlConnection instance, you are not opening a new physical connection to the database, you are simply drawing one from the existing pool. And when you call Close you are not closing the connection, you are simply returning it to the connection pool for reuse.
The connection pool lives in the process of your application and is per connection string.
Do we need to clear these processes explicitly?
No, all you have to do is to ensure that you have wrapped all your IDisposable resources (such as as connections and commands) in using statements. This way you don't even need to be explicitly calling the Close method and the code will ensure that everything is properly disposed even in case of exception:
string connectionString = ...
using (var conn = new SqlConnection(connectionString))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "SELECT id FROM foo";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
int id = reader.GetInt32(reader.GetOrdinal("id"));
Console.WriteLine(id);
}
}
}

Make sure you dispose the connection, your best bet is a using()-block.
using ( var con = new SqlConnection("???") )
{
using ( var cmd = con.CreateCommand() )
{
// do SQL with cmd
}
}

Related

How to keep single SQL Server connection instance open for multiple request in C#?

I have a Web API which contains database insert logic (ado.net) in C#. When multiple users (e.g. 100 users) call the Web API, every time a SQL Server connection is opened and closed for multiple requests. It slows down performance.
How can I keep a single SQL Server connection live for multiple requests? I have to keep SQL connection open only once and close after some time so that during that time it should consider multiple request and insert records in database.
Please suggest.
ADO.NET's SqlConnection is implementing a connection pool.
This means that when you close or dispose an instance of SqlConnection, the underlying connection simply returns to the pool. When another instance of SqlConnection is opened, and a connection is available in the connection pool, that connection will be used.
In fact, Microsoft docs page on SQL Server Connection Pooling clearly states:
Caution
We strongly recommend that you always close the connection when you are finished using it so that the connection will be returned to the pool. You can do this using either the Close or Dispose methods of the Connection object, or by opening all connections inside a using statement in C#, or a Using statement in Visual Basic. Connections that are not explicitly closed might not be added or returned to the pool. For more information, see using Statement or How to: Dispose of a System Resource for Visual Basic.
This means that the best practice way of using SqlConnection is this:
using(var con = new SqlConnection(connectionString))
{
// your sql stuff goes here...
}
BTW, SqlCommand, SqlDataReader and SqlDataAdapter also implements the IDisposable interface, so they too needs to be used in the context of the using statement:
using(var con = new SqlConnection(connectionString))
{
using(var cmd = new SqlCommand(sql, con))
{
// prepare command here - parameters and stuff like that
// either
using(var reader = cmd.ExecuteReader())
{
}
// or
using(var adapter = new SqlDataAdapter(cmd))
{
}
}
}
Well it's easy you just have to keep the connection open and if any readers opened they are closed.
var con = new SqlConnection("Your connection String");
con.open();
//your code
con.close()//after you have done your executions
Have you tried Linq. It does the same thing you want, it keeps the connection alive and i think it'll be easier for you

There is already an open DataReader associated with this Connection which must be closed first error in c# [duplicate]

I have below code and I am getting exception:
There is already an open DataReader associated with this Connection which must be closed first.
I am using Visual Studio 2010/.Net 4.0 and MySQL for this project. Basically I am trying to run another SQL statement while using data reader to do my other task. I am getting exception at line cmdInserttblProductFrance.ExecuteNonQuery();
SQL = "Select * from tblProduct";
//Create Connection/Command/MySQLDataReader
MySqlConnection myConnection = new MySqlConnection(cf.GetConnectionString());
myConnection.Open();
MySqlCommand myCommand = new MySqlCommand(SQL, myConnection);
MySqlDataReader myReader = myCommand.ExecuteReader();
myCommand.Dispose();
if (myReader.HasRows)
{
int i = 0;
// Always call Read before accessing data.
while (myReader.Read())
{
if (myReader["frProductid"].ToString() == "") //there is no productid exist for this item
{
strInsertSQL = "Insert Into tblProduct_temp (Productid) Values('this istest') ";
MySqlCommand cmdInserttblProductFrance = new MySqlCommand(strInsertSQL, myConnection);
cmdInserttblProductFrance.ExecuteNonQuery(); //<=====THIS LINE THROWS "C# mySQL There is already an open DataReader associated with this Connection which must be closed first."
}
}
}
You are using the same connection for the DataReader and the ExecuteNonQuery. This is not supported, according to MSDN:
Note that while a DataReader is open, the Connection is in use
exclusively by that DataReader. You cannot execute any commands for
the Connection, including creating another DataReader, until the
original DataReader is closed.
Updated 2018: link to MSDN
Always, always, always put disposable objects inside of using statements. I can't see how you've instantiated your DataReader but you should do it like this:
using (Connection c = ...)
{
using (DataReader dr = ...)
{
//Work with dr in here.
}
}
//Now the connection and reader have been closed and disposed.
Now, to answer your question, the reader is using the same connection as the command you're trying to ExecuteNonQuery on. You need to use a separate connection since the DataReader keeps the connection open and reads data as you need it.
Just use MultipleActiveResultSets=True in your connection string.
Add MultipleActiveResultSets=true to the provider part of your connection string
example in the file appsettings.json
"ConnectionStrings": {
"EmployeeDBConnection": "server=(localdb)\\MSSQLLocalDB;database=YourDatabasename;Trusted_Connection=true;MultipleActiveResultSets=true"}
You are trying to to an Insert (with ExecuteNonQuery()) on a SQL connection that is used by this reader already:
while (myReader.Read())
Either read all the values in a list first, close the reader and then do the insert, or use a new SQL connection.
The issue you are running into is that you are starting up a second MySqlCommand while still reading back data with the DataReader. The MySQL connector only allows one concurrent query. You need to read the data into some structure, then close the reader, then process the data. Unfortunately you can't process the data as it is read if your processing involves further SQL queries.
This exception also happens if you don't use transaction properly. In my case, I put transaction.Commit() right after command.ExecuteReaderAsync(), did not wait with the transaction commiting until reader.ReadAsync() was called. The proper order:
Create transaction.
Create reader.
Read the data.
Commit the transaction.
You have to close the reader on top of your else condition.
In my case, I was awaiting an async call, but in the calling scope, I was not awaiting that method that I was making the call in. So, the calling scope was continuing on while my connection was still open.
called scope:
protected override async Task AfterProcessing()
{
var result = await Stats.WriteAsync();
Log.Information("Stopping");
}
calling scope:
public virtual async Task Run()
{
BeforeProcessing();
try
{
Process();
}
finally
{
AfterProcessing(); // this line was missing an "await"
}
}
There is another potential reason for this - missing await keyword.

Do I need to close OleDbDataReader everytime I use it?

I am using the OleDbDataReader class in my c# project and my program keep locking up my mdb file after it runs. I am wondering how do I close my connection reliably at the end to release the lock. And if I need to close it everytime I run a query or can I just do it all in one go at the end of the program. Here is how I am setting it up:
private OleDbConnection myDbC = new OleDbConnection(connectionString);
myDbC.Open();
And here is how I use it, many many times:
OleDbCommand cmd = new OleDbCommand(SQL, myDbC);
OleDbDataReader reader = cmd.ExecuteReader();
reader.Close();
When the program finishes, I also do the following:
myDbC .Close();
So this is somehow locking up the mdb file. Any help?
I suggest you to use using keyword. Because sometimes you can forget to close or dispose connection and reader. Because using automatically disposes object. Using statement tells .NET to release the object specified in the using block once it is no longer needed.
using (OleDbConnection conn = /* Create new instance using your favorite method */)
{
conn.Open();
using (OleDbCommand command = /* Create new instance using your favorite method */)
{
using (OleDbDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
//read here
}
}
}
conn.Close(); // Optional
}
Additional details from MSDN:
C#, through the .NET Framework common language runtime (CLR),
automatically releases the memory used to store objects that are no
longer required. The release of memory is non-deterministic; memory is
released whenever the CLR decides to perform garbage collection.
However, it is usually best to release limited resources such as file
handles and network connections as quickly as possible.
The using statement allows the programmer to specify when objects that
use resources should release them. The object provided to the using
statement must implement the IDisposable interface. This interface
provides the Dispose method, which should release the object's
resources.
It is always a good practice to .Close() connections. Do NOT rely on the Garbage Collector to do it for you. There are certain situations where the connection will automatically close for you; like when using a SqlDataAdapter and its .Fill() method. But that doesn't change the fact that you should manage your connections in your code.
That being said, this is best achieved with a using statement, like this:
using(OleDbConnection oledbConn = new OleDbConnection())
{
oledbConn.Open();
}
You can also nest these using statements, wrap command objects and even data adapters:
using(OleDbConnection oleDbConn = new OleDbConnection())
{
oleDbConn.Open();
using (OleDbCommand oleDbCmd = new OleDbCommand())
{
using (OleDbDataAdapter oleDbAdapter = new OleDbDataAdapter())
{
//More code can go here.
}
}
oleDbConn.Close();
}

Exception: There is already an open DataReader associated with this Connection which must be closed first

I have below code and I am getting exception:
There is already an open DataReader associated with this Connection which must be closed first.
I am using Visual Studio 2010/.Net 4.0 and MySQL for this project. Basically I am trying to run another SQL statement while using data reader to do my other task. I am getting exception at line cmdInserttblProductFrance.ExecuteNonQuery();
SQL = "Select * from tblProduct";
//Create Connection/Command/MySQLDataReader
MySqlConnection myConnection = new MySqlConnection(cf.GetConnectionString());
myConnection.Open();
MySqlCommand myCommand = new MySqlCommand(SQL, myConnection);
MySqlDataReader myReader = myCommand.ExecuteReader();
myCommand.Dispose();
if (myReader.HasRows)
{
int i = 0;
// Always call Read before accessing data.
while (myReader.Read())
{
if (myReader["frProductid"].ToString() == "") //there is no productid exist for this item
{
strInsertSQL = "Insert Into tblProduct_temp (Productid) Values('this istest') ";
MySqlCommand cmdInserttblProductFrance = new MySqlCommand(strInsertSQL, myConnection);
cmdInserttblProductFrance.ExecuteNonQuery(); //<=====THIS LINE THROWS "C# mySQL There is already an open DataReader associated with this Connection which must be closed first."
}
}
}
You are using the same connection for the DataReader and the ExecuteNonQuery. This is not supported, according to MSDN:
Note that while a DataReader is open, the Connection is in use
exclusively by that DataReader. You cannot execute any commands for
the Connection, including creating another DataReader, until the
original DataReader is closed.
Updated 2018: link to MSDN
Always, always, always put disposable objects inside of using statements. I can't see how you've instantiated your DataReader but you should do it like this:
using (Connection c = ...)
{
using (DataReader dr = ...)
{
//Work with dr in here.
}
}
//Now the connection and reader have been closed and disposed.
Now, to answer your question, the reader is using the same connection as the command you're trying to ExecuteNonQuery on. You need to use a separate connection since the DataReader keeps the connection open and reads data as you need it.
Just use MultipleActiveResultSets=True in your connection string.
Add MultipleActiveResultSets=true to the provider part of your connection string
example in the file appsettings.json
"ConnectionStrings": {
"EmployeeDBConnection": "server=(localdb)\\MSSQLLocalDB;database=YourDatabasename;Trusted_Connection=true;MultipleActiveResultSets=true"}
You are trying to to an Insert (with ExecuteNonQuery()) on a SQL connection that is used by this reader already:
while (myReader.Read())
Either read all the values in a list first, close the reader and then do the insert, or use a new SQL connection.
The issue you are running into is that you are starting up a second MySqlCommand while still reading back data with the DataReader. The MySQL connector only allows one concurrent query. You need to read the data into some structure, then close the reader, then process the data. Unfortunately you can't process the data as it is read if your processing involves further SQL queries.
This exception also happens if you don't use transaction properly. In my case, I put transaction.Commit() right after command.ExecuteReaderAsync(), did not wait with the transaction commiting until reader.ReadAsync() was called. The proper order:
Create transaction.
Create reader.
Read the data.
Commit the transaction.
You have to close the reader on top of your else condition.
In my case, I was awaiting an async call, but in the calling scope, I was not awaiting that method that I was making the call in. So, the calling scope was continuing on while my connection was still open.
called scope:
protected override async Task AfterProcessing()
{
var result = await Stats.WriteAsync();
Log.Information("Stopping");
}
calling scope:
public virtual async Task Run()
{
BeforeProcessing();
try
{
Process();
}
finally
{
AfterProcessing(); // this line was missing an "await"
}
}
There is another potential reason for this - missing await keyword.

Is there a way to create an ADO.NET connection and ignore the ambient Transaction?

I have a situation where I am running in a WCF service that has TransactionScopeRequired=true, which means there will always be an ambient transaction.
However, I need to start a new connection that will be around for the lifetime of the application, which means I can't have it use the abmbient transaction.
Any ideas on how to do this? Just doing this will automatically use the ambient transaction:
Assert.IsNotNull(System.Transactions.Transaction.Current);
var conn = new OracleConnection("my connection string");
conn.Open(); // <-- picks up ambient transaction, but I don't want that
Actually the example could be made simpler by saying this:
OracleConnection conn; // <-- this is actually held around in another object that has a very long lifetime, well past the TransactionScope.
using(var tx = new TransactionScope())
{
conn = new OracleConnection("my connection string");
conn.Open(); // <-- picks up ambient transaction, but I don't want that
// ... do stuff
}
I don't want my connection to actually pick up the TransactionScope. In the actual code there is a lot more going on that does do DB actions within the scope, I just have 1 that I need to keep around past the lifetime of the transaction scope.
I guess the real situation is worth mentioning. What actually happens here is that during a WCF service call, I add an object to a cache using the Enterprise Library Caching block. This object is a data table, but also holds on to an open connection to Oracle that has Continuous Notification set up. This gives me the ability to automatically refresh my cached dataset when the underlying Oracle tables change.
The data cache item can be accessed by any number of WCF initialized threads, all of which run in their own transaction scope. I guess you could think of it as putting an OracleConnection object in a cache. A better block of text/exampe code would be like:
//beginning of a WCF service call
using (var tx = new TransactionScope())
{
var conn = new OracleConnection();
var cmd = new OracleCommand();
// set up OCN on the cmd and connection
var reader = cmd.ExecuteReader();
cache.Add("conn", conn);
cache.Add("cmd", cmd);
}
//beginning of a second wcf service call
using (var tx = new TransactionScope())
{
var conn = cache.Get("conn");
var cmd = cache.Get("cmd");
var reader = cmd.ExecuteReader();
// user reader to reload some data
}
Point being I have a connection that has a long lifetime across multiple threads and transaction scopes.
Have you tried one of the TransactionScope constructors that allows you to set the scope? Setting the scope to "Requires New" creates a new transaction for your connection to enlist in. Setting the scope to "Suppress" makes it so that your connection doesn't enlist in any transaction. At least, thats how I read the documentation. I've never had that specific need, myself.
using(var tx = new TransactionScope(TransactionScopeOption.RequiresNew))
{
conn = new OracleConnection("my connection string");
conn.Open();
}

Categories

Resources