OleDbConnection.Close() does not work - c#

I have a method where I insert some data in a local MDB-Acces file. With this code it works fine:
try
{
foreach (DataRow rowS99 in dtS99.Rows)
{
con.Open();
da.InsertCommand = con.CreateCommand();
da.InsertCommand.Parameters.AddWithValue("#wertListName", rowS99["WertListName"]);
da.InsertCommand.Parameters.AddWithValue("#key", rowS99["Key"]);
da.InsertCommand.Parameters.AddWithValue("#bezeichner", rowS99["Bezeichner"]);
da.InsertCommand.Parameters.AddWithValue("#keyAufbereitet", rowS99["KeyAufbereitet"]);
da.InsertCommand.CommandText = sql;
da.InsertCommand.ExecuteNonQuery();
con.Close();
}
check = true;
}
When i put the Open and Close method outside the foreach loop the code works, but the local file, which was used with the connection, is already opened with Visual Studio so that i can't delete or move it. The Status of the connection says after con.Close() that it is closed.
What is the problem here?

You don't need to have the Connection Opened and Closed within the loop. If there are 500 rows in your table then you will be opening & closing the connection 500 times, its not best practice..
Your connection should open in the Try statement before the loop and close once all Rows have been processed.
I think you would be best using the Update() function rather than the method your doing above.
You can take out the need to loop through each and every row.
http://msdn.microsoft.com/en-us/library/system.data.common.dataadapter.update.aspx
Using this functionality allows you to add, edit and delete rows simply by calling the Update() method. You will need all 3 Commands setting up, UPDATE, INSERT, DELETE.
Hope this helps

IDbConnection.Close method by default just returns connection back to the connection pool. It doesn't close the physical connection (either network connection or file). You may disable connection pooling (but this will decrease productivity of your application), or clear connection pool (see OleDbConnection.ReleaseObjectPool).

Try to put con.close in finally().

try
{
con.Open();
foreach (DataRow rowS99 in dtS99.Rows)
{
da.InsertCommand = con.CreateCommand();
da.InsertCommand.Parameters.AddWithValue("#wertListName", rowS99["WertListName"]);
da.InsertCommand.Parameters.AddWithValue("#key", rowS99["Key"]);
da.InsertCommand.Parameters.AddWithValue("#bezeichner", rowS99["Bezeichner"]);
da.InsertCommand.Parameters.AddWithValue("#keyAufbereitet", rowS99["KeyAufbereitet"]);
da.InsertCommand.CommandText = sql;
da.InsertCommand.ExecuteNonQuery();
}
con.Close();
check = true;
OleDb.OleDbConnection.ReleaseObjectPool();
GC.Collect(); // I know attation
}
Works for me

Related

C# MySql: Location of opening DataReader [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.

How to run SQL File having large number of lines?

I am having a SQL file(filenameScript) having more than 10k lines of code. Each block of SQL starts with GO and ends with GO. While executing the file from C#, I am getting exception near GO statements. But when I am running the same file in SQL server it is working fine.
con.ConnectionString = sqlconn;
FileInfo file = new FileInfo(filenameScript);
string script = file.OpenText().ReadToEnd();
SqlCommand command = new SqlCommand(script, con);
con.Open();
command.ExecuteNonQuery();
Close();
I think ExecuteNonQuerry is not able to handle so many \n,\r,and \t as the file read is stored in single line with many \n and \r.
Is there any other method to do the same?
Thanks in advance.
No, the issue is not the length of the file, nor is it the existence of \r and/or \n characters. It is because executing SQL using that method can only run a single batch, and the script having GO statements causes multiple batches.
One possibility is to split the text on the keyword GO and execute each individual part:
con.ConnectionString = sqlconn;
var commands = File.ReadAllText(filenameScript).Split(new []{"GO"},StringSplitOption.RemoveEmptyEntries);
con.Open();
foreach(var batch in commands)
{
SqlCommand command = new SqlCommand(batch, con);
command.ExecuteNonQuery();
}
con.Close()
Additionally, you could wrap that in a Transaction to ensure all batches are executed atomically.
An alternative is also provided in this SO Question: How do I execute a large SQL script (with GO commands) from c#

sql statement isnt saving any data into table

Whenever I execute my C# code everything goes well, no compiler errors, nothing.
But when I go to look at my table in the server explorer, nothing was inserted.
Restarted Visual Studio, still nothing.
I went to debug and I looked at the cmd string before it executes ExecuteNonQuery() and the string still is #itmId,... etc. Not sure if that would effect it or not. Any help?
try
{
Item workingItem = mItemList.Items[itemCombo.SelectedIndex - 1] as Item;
SqlCeConnection sc = new SqlCeConnection(SalesTracker.Properties.Settings.Default.salesTrackerConnectionString);
SqlCeCommand cmd = new SqlCeCommand("INSERT INTO Sales VALUES(#itmId, #itmNm,#fstNm, #date,#prft, #commision)", sc);
cmd.Parameters.AddWithValue("#itmId", workingItem.ItemId);
cmd.Parameters.AddWithValue("#itmNm", workingItem.ItemName);
cmd.Parameters.AddWithValue("#fstNm", logedSalesmen.ID);
cmd.Parameters.AddWithValue("#date", DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));
cmd.Parameters.AddWithValue("#prft", workingItem.Profit);
cmd.Parameters.AddWithValue("#commision", workingItem.Commision);
sc.Open();
cmd.ExecuteNonQuery();
sc.Close();
MessageBox.Show("Save successfull");
this.Close();
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
}
EDIT:So it is a matter of the temporary debug database being used, i used select count(0) to figure that out. But im not sure what i should use in my connection string to fix it.
The most common error here is actually a deployment thing - i.e. having 2 different database files in play. In particular, commonly the database file you are debugging (etc) against is often the one in "bin/debug" or similar, and gets overwritten every time you build. But the file people often look at to see the change is the one in their project tree.
Make sure you are looking at the right file.
The code looks fine; the fact that the parameters are still parameters is entirely expected and correct. If you want a simple way of validating the insert, then just check
SELECT COUNT(1) FROM Sales
before and after the insert; I expect it will be incrementing.
Also check that you are closing and disposing the connection cleanly (in case this is simply a buffered change that didn't get written before the process terminated). Both sc and cmd are IDisposable, so you should use using really:
using(SqlCeConnection sc = new SqlCeConnection(
SalesTracker.Properties.Settings.Default.salesTrackerConnectionString))
using(SqlCeCommand cmd = new SqlCeCommand(
"INSERT INTO Sales VALUES(#itmId, #itmNm,#fstNm, #date,#prft, #commision)",
sc))
{
cmd.Parameters.AddWithValue("#itmId", workingItem.ItemId);
cmd.Parameters.AddWithValue("#itmNm", workingItem.ItemName);
cmd.Parameters.AddWithValue("#fstNm", logedSalesmen.ID);
cmd.Parameters.AddWithValue("#date",
DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));
cmd.Parameters.AddWithValue("#prft", workingItem.Profit);
cmd.Parameters.AddWithValue("#commision", workingItem.Commision);
sc.Open();
cmd.ExecuteNonQuery();
}
You shouldn't convert DateTime.Now to a string - pass it just as DateTime.Now
You should specify the columns in your insert statement: Ie:
INSERT INTO Sales (ItemID,ItemName...) VALUES (#itmID)
You can use SQL Profiler to check what is being passed to the Database.
Visual Studio can sometimes copy SQLCE databases when you don't want it to, when you build your C# project. So, click on the sdf file in the Solution Explorer and select Copy if newer.

Using database connection in separate form

I have my main form which has a datagrid view connected to a database. Then I have a button that opens a separate form and I've got a few buttons etc on that secondary form.
I need to query the database from the secondary form but I'm not sure how to do that without creating a whole new connection, which I don't think I need since the program is already connected to the database. I'm just not sure how to reference the oleDB connection I made in that first form (I didn't code it in, I used the little arrow on the datagridview to connect it to the database using visual studio)
Now instead of creating that new connection, how do I reference the first connection made in the primary form?
Here is my code:
//parameterized update query
string updateCommandString = "UPDATE RoomsTable SET [Date Checked]=#checkedDate WHERE ID = #id";
using (OleDbConnection conn = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=c:\users\spreston\documents\visual studio 2012\Projects\roomChecksProgram\roomChecksProgram\roomsBase.accdb"))
{
using (OleDbCommand updateCommand = new OleDbCommand())
{
OleDbTransaction transaction = null;
updateCommand.Connection = conn;
updateCommand.Transaction = transaction;
updateCommand.CommandText = updateCommandString;
updateCommand.CommandType = CommandType.Text;
updateCommand.Parameters.AddWithValue("#checkedDate", this.dateTimePicker1.Value.ToShortDateString());
updateCommand.Parameters.AddWithValue("#id", row.roomID);
try
{
conn.Open();
transaction = conn.BeginTransaction();
updateCommand.Transaction = transaction;
updateCommand.ExecuteNonQuery();
transaction.Commit();
conn.Close();
conn.Dispose();
}
catch(OleDbException ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
}
From a design standpoint, you should consider making a data access layer for your forms to utilize. You can create methods to retrieve those Db results for you so you consolidate that code and separate it from your form functionality. It may be just a small project, but it's good practice and if it's a project you want to grow, you'll want it laid out to be extendable.
Something like
class SomethingDA {
static DataTable GetMyStuff(your params) {
// establish connection, get your results
}
}
You can then call SomethingDa.GetMyStuff() to get what you need.
If you are Using the "Using" statement, your connection is closed after this code is run. You don't in fact need the conn.Close() and conn.Dispose() statements. Using does that for you.
Your best bet is to open up the connection again. It is generally a good practice to open and close connections as quickly as possible, although likely less important if your Access DB local. This generally does not impact performance too much as the OLE DB driver behind the scene will pool the connection and keep it open for a period of time.

SQL connection to database repeating

ok now i am using the SQL database to get the values from different tables... so i make the connection and get the values like this:
DataTable dt = new DataTable();
SqlConnection connection = new SqlConnection();
connection.ConnectionString = ConfigurationManager.ConnectionStrings["XYZConnectionString"].ConnectionString;
connection.Open();
SqlCommand sqlCmd = new SqlCommand("SELECT * FROM Machines", connection);
SqlDataAdapter sqlDa = new SqlDataAdapter(sqlCmd);
sqlCmd.Parameters.AddWithValue("#node", node);
sqlDa.Fill(dt);
connection.Close();
so this is one query on the page and i am calling many other queries on the page.
So do i need to open and close the connection everytime...???
also if not this portion is common in all:
DataTable dt = new DataTable();
SqlConnection connection = new SqlConnection();
connection.ConnectionString = ConfigurationManager.ConnectionStrings["XYZConnectionString"].ConnectionString;
connection.Open();
can i like put it in one function and call it instead.. the code would look cleaner...
i tried doing that but i get errors like:
Connection does not exist in the current context.
any suggestions???
thanks
You can definitely share the "open connection" code, no reason to duplicate it.
With the SQL Server provider for ASP.NET, there is very little overhead with "closing" the connection every time. It just returns the connection to your process' connection pool (see here), so opening the next connection will use very little overhead. I think it is good practice to close the connection after each operation
I use "using". You can include as many queries as you like inside. When complete it will clean up for you.
using (SqlConnection cn = new SqlConnection(connectionString))
{
using (SqlCommand cm = new SqlCommand(commandString, cn))
{
cn.Open();
cm.ExecuteNonQuery();
}
}
Typically yes, you make individual connections for multiple rowsets.
If you can use joins to produce a single meaningful rowset, that's typically a good thing to do on the server side instead of the client side.
You may also want to look at making multiple connections and using the async features in order to queue all your requests simultaneously instead of sequentially - have a look at this article.
No you do not have to open and close the connection every time as long as you are using the same database. What you need to change is the
sqlCommand's queryString every time.
Like what #durilai said, [using] is useful. Using actually has more functions than this, but essentially it puts a try/catch block around your code and calls dispose to close the connection in this case.
Anything that needs open/close can be used with using, so things such as text writers, or other objects.

Categories