I've been fighting with OleDbConnection for a while now trying to get it to not cache. Basically I am accessing a shared Access database, which is being written to from another application, and then I'm reading back values (having checked that it is flushed via the Last Write time and a subsequent 1 second delay).
Unfortunately, this is entirely unreliable.
I've been reading (and going insane) how to disable the connection pooling, and am subsequently, after each possible update, performing the following before reconnecting:
_connection.Close();
_connection.Dispose();
_connection = null;
OleDbConnection.ReleaseObjectPool();
GC.Collect();
In addition to this, the connection string disables connection pooling with OLE DB Services = -2. Finally, I have also changed PageTimeout to '10' in the registry for Jet 4.0.
All of these measures are unfortunately having no effect. Now the only thing I can think of doing is what is mentioned in this Microsoft KB Article, and call JRO.JetEngine.RefreshCache. The only issue with that is that it's argument is an ADODB.Connection. I'd rather not rewrite my whole database layer and where the records are being read by my software to use a legacy COM object just to have this functionality, but it appears that it may well be the only way.
My question is, whilst currently undergoing this task of rewriting to use ADODB (not even ADO.NET!), is it possible to disable the caching of an OleDbConnection?
Finally, I found a workaround: Use OdbcConnection instead of OleDbConnection.
This is the old code:
string mdbConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + mdbFile + ";OLE DB Services=-2";
using (OleDbConnection conn = new OleDbConnection(mdbConnectionString)) {
conn.Open();
//Do your query
}
And this is new one:
string mdbConnectionString = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};Dbq=" + mdbFile;
using (OdbcConnection conn = new OdbcConnection(mdbConnectionString)) {
conn.Open();
//Do your query
}
All things work fine.
You might have some luck setting the ";Jet OLEDB:Flush Transaction Timeout" property to 0 or some low number.
See documentation.
32-bit application
In a 32-bit C# application, I'm doing this since years to refresh the cache:
public static void RefreshDatabaseCache(
string connectionString)
{
// The type of the ADODB connection. Used for dynamically creating.
var adodbType = Type.GetTypeFromProgID(#"ADODB.Connection");
// The main ADODB connection object.
var adodbInstance = Activator.CreateInstance(adodbType);
// --
// Open the connection.
adodbType.InvokeMember(
#"Open",
BindingFlags.InvokeMethod,
null,
adodbInstance,
new object[]
{
connectionString,
string.Empty,
string.Empty,
0
});
try
{
// The type of the JET engine. Used for dynamically creating.
var jroType = Type.GetTypeFromProgID(#"JRO.JetEngine");
// The main JET engine object.
var jroInstance = Activator.CreateInstance(jroType);
// Refresh the cache.
jroType.InvokeMember(
#"RefreshCache",
BindingFlags.InvokeMethod,
null,
jroInstance,
new[]
{
adodbInstance
});
}
finally
{
// Close the connection.
adodbType.InvokeMember(
#"Close",
BindingFlags.InvokeMethod,
null,
adodbInstance,
new object[]
{
});
}
}
I'm using OleDB in my whole application, just inside the above function, I'm using this "ADODB" thing.
64-bit application
In a 64-bit C# application I currently do know no way of doing this.
Related
I want to create a connection for my UWP and database. I want the uwp to send a value to the database.
MySql.Data.MySqlClient.MySqlConnection conn;
string myConnectionString;
myConnectionString = "server=127.0.0.1; uid = root;" + "pwd=root;database=test";
try
{
conn = new MySql.Data.MySqlClient.MySqlConnection(myConnectionString);
conn.Open();
}
catch (MySql.Data.MySqlClient.MySqlException ex)
{
}
Is this the correct way to write the connection ? and where do I write this part of the coding at ?
enter image description here
Main page or any of my other page ? (scenario 1-3)
Your content looks right, I would try to use 'localhost' rather than ip.
var myConnection = new MySqlConnection();
myConnection.ConnectionString = "database=test;server=localhost;uid=root;pwd=root";
myConnection.Open();
More info see: https://dev.mysql.com/doc/dev/connector-net/6.10/html/P_MySql_Data_MySqlClient_MySqlConnection_ConnectionString.htm
I would also check here to see if you are providing enough info, which you are. https://www.connectionstrings.com/mysql/
In terms of connecting to the database, it depends. What type of application is this? Typically, database connections are made during the start of the application. If you are using Entity Framework, you'll want your Database Context to manage the connection (which is an entirely different topic).
I have a function that connects to a Excel File:
public OleDbConnection connection;
public void eConnection(string srcString, string id)
{
conString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + srcString + "; Extended Properties='Excel 8.0;HDR=Yes;IMEX=1'";
connection = new OleDbConnection(conString);
connection.Open();
}
I want to create another function that will close this existing connection when called or invoke
This is what I have to try and close the existing connection:
public void eCloseConnection()
{
connection.Close();
}
How can I close the existing connection using a function that calls the same connection and closes it
How can I test to see if the connection is closed?
Don't do it like this. OleDbConnection implements the IDisposable interface should be disposed as soon as you are done using it, and the best way to do it is to use it as a local variable declared in a using statement:
public void DoStuffWithExcel(string srcString)
{
conString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + srcString + "; Extended Properties='Excel 8.0;HDR=Yes;IMEX=1'";
using(var connection = new OleDbConnection(conString))
{
connection.Open();
// do your stuff here...
}
}
The using statement ensures the connection will be disposed properly even if an exception occurs inside the using block.
This way is the best way to prevent memory leaks, as well as to use the connection pool.
From Microsoft docs page OLE DB, ODBC, and Oracle Connection Pooling:
We recommend that you always close or dispose of a connection when you are finished using it in order to return the connection to the pool. Connections that are not explicitly closed may not get returned to the pool. For example, a connection that has gone out of scope but that has not been explicitly closed will only be returned to the connection pool if the maximum pool size has been reached and the connection is still valid.
Don't keep a global object for a connection hidden inside a class. This adds more problems than the one solved. You should keep track how many time that code is called and how many connection it creates. And of course this makes a lot more complicated the closing part.
Instead the C# language offers a better approach to this kind of problem. An approach particularly suited for objects like a connection that requires unmanaged resources to be realeased to the OS as soon as possible.
You should instead use this approach both if you want to have a class that handles your connections or if you just want to open and use a connection
public static class DbUtility
{
public static OleDbConnection eConnection(string srcString)
{
conString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + srcString + "; Extended Properties='Excel 8.0;HDR=Yes;IMEX=1'";
connection = new OleDbConnection(conString);
connection.Open();
return connection;
}
.... other static utilities
}
Now you can use your class in this way
string srcFile = #"d:\temp\myFile.xlsx";
using(OleDbConnection cn = DbUtility.eConnection(srcFile))
{
.. use your connection
} // <- at this point your connection is automatically closed and disposed.
The using keyword is of great help when you need to just destroy your disposable objects like a connection. In this way you don't keep a global object around when you don't need it.
can't I open new data reader in existing data reader?? plzz help me. i'm new to c#
string statement11 = "SELECT Planning FROM allow where NPLID=(SELECT MAX(NPLID) FROM allow)";
SqlCommand myCommand11 = new SqlCommand(statement11, con1);
SqlDataReader plan2 = myCommand11.ExecuteReader();
while(plan2.Read())
if (!plan2.IsDBNull(0) && "ok" == plan2.GetString(0))
{
string statement99 = "SELECT Dropplan FROM NPLQAnew where NPLID=(SELECT MAX(NPLID) FROM allow)";
SqlDataReader myReader1 = null;
SqlCommand myCommand114 = new SqlCommand(statement99, con1);
SqlDataReader plandrop = myCommand114.ExecuteReader();
while (plandrop.Read())
if (plandrop.IsDBNull(0) && plandrop.GetString(0) == "Red")
{
Lblplan1.BackColor = System.Drawing.Color.Red;
}
else if (plandrop.IsDBNull(0) && "amber" == plandrop.GetString(0))
{
Lblplan1.BackColor = System.Drawing.Color.Orange;
}
else if (plandrop.IsDBNull(0) && "Green" == plandrop.GetString(0))
{
Lblplan1.BackColor = System.Drawing.Color.Green;
}
plandrop.Close();
this.Lblplan1.Visible = true;
}
plan2.Close();
By default, the SQL Server client will not let you open two simultaneous queries on the same connection. If you are in the process of reading the results of one data reader, for example, you cannot use the same connection to start reading from a second. And, with the way that SQL Server connection pooling works, even asking for a "new" connection is not guaranteed to work either.
You have a couple of options on how to fix this. The first is to refactor your code to eliminate the nested SQL execute calls; for example, load the results of your first query into memory before you loop through and process them.
An easier answer is to enable "MARS" - Multiple Active Recordsets - on your connection. This is done be setting the "MARS Connection=True option on the connection string to turn the feature on. This is generally pretty safe to do, and it's only off by default to preserve the pre-2005 behavior for old applications, but you the linked article does give some guidelines.
You can try setting MultipleActiveResultSets=True in your connection string
No you cant perform this on same connection, but you can achieve by
Multiple Active Result Sets (MARS), am hoping you having sqlserver 2005 and above.
or
You need to different connection to be opened for the second command.
Use USING statement. The using statement calls the Dispose method on the object in the correct way, and it also causes the object itself to go out of scope as soon as Dispose is called.
For error : There is already data reader attached to current connection string. Try to close the data reader first.
after this line
if (!plan2.IsDBNull(0) && "ok" == plan2.GetString(0))
{
//open a new sql connection here
//your string statement99
:
:
// then close your second sql connection here before the last }
}
I want to know if a multiple active result set, MARS, exists for the Microsoft's Access database? I am aware this exists for SQL Server. I tried using it with Access but it didn't work for me. I want to know how to use MARS with Access.
In short, Microsoft Access does not support multiple active result sets (MARS). It is not supported by the ODBC provider and the reason why that is not the case should be obvious if you think about it in terms of what MARS actually offers you from a performance stand point.
If you think about the most important reason for MARS to exist is if you have stored procedures executed on a SQL server that produce multiple result sets. If you have such queries you need to be able to somehow access those multiple results sets.
But in Access there is no such thing as stored procedures. If you have multiple queries you can just execute each one of them separately and get the result set for each. Hence, no need for MARS.
NOTE
In light of the comments, here's an example of how to have two data readers open at the same time:
using(var connection1 = new OdbcConnection("your connection string here"))
{
connection1.Open();
using(var connection2 = new OdbcConnection("your connection string here"))
{
connection2.Open();
using(var cmd1 = connection1.CreateCommand())
{
cmd1.CommandText = "YOU FIRST QUERY HERE";
using(var dataReader1 = cmd1.ExecuteReader())
{
while(dataReader1.Read())
{
// keep reading data from dataReader1 / connection 1
// .. at some point you may need to execute a second query
using(var cmd2 = connection2.CreateCommand())
{
cmd2.CommandText = "YOUR SECOND QUERY HERE";
// you can now execute the second query here
using(var dataReader2 = cmd2.ExecuteReader())
{
while(dataReader2.Read())
{
}
}
}
}
}
}
connection2.Close();
}
connection1.Close();
}
i have the code below trying to do a bulk copy from oracle to SQL server 2005 and it keeps timing out. how can i extend the oracle connection timeout? it seems i can not from what i read on the web.
OracleConnection source = new OracleConnection(GetOracleConnectionString());
source.Open();
SqlConnection dest = new SqlConnection(GetSQLConnectionString() );
dest.Open();
OracleCommand sourceCommand = new OracleCommand(#"select * from table");
using (OracleDataReader dr = sourceCommand.ExecuteReader())
{
using (SqlBulkCopy s = new SqlBulkCopy(dest))
{
s.DestinationTableName = "Defects";
s.NotifyAfter = 100;
s.SqlRowsCopied += new SqlRowsCopiedEventHandler(s_SqlRowsCopied);
s.WriteToServer(dr);
s.Close();
}
}
source.Close();
dest.Close();
here is my oracle connection string:
return "User Id=USER;Password=pass;Data Source=(DESCRIPTION=" +
"(ADDRESS=(PROTOCOL=TCP)(HOST=14.12.7.2)(PORT=1139))" +
"(CONNECT_DATA=(SID=QCTRP1)));";
You can set s.BulkCopyTimeout option
In your connection string, there is a 'Connection Lifetime' and 'Connection Timeout' parameter. You can set it accordingly. See here for the full reference.
BTW, I know you didn't ask this, but have you considered an ETL tool for migrating your DB records (e.g. Informatica, FME, etc.)? While your approach is valid, it isn't going to be very performant since you are hydrating all of the records from one DB to the client and then serializing them to another DB. For small bulk sets, this isn't a big issue, but if you were processing hundreds of thousands of rows, you might want to consider an official ETL tool.