I have a special situation where I must disconnect and reconnect from the Oracle database. (I must check whether my connection string is still working, i.e. whether my password is still valid.)
Unfortunately, though, connection.Close() doesn't close the session. When I reconnect with a new connection, I am getting my old session back.
Here is my code:
using Oracle.ManagedDataAccess.Client;
...
string connectionString = "Data Source=mydb;User Id=myuser;Password=\"mypwd\";";
using (OracleConnection connection = new OracleConnection())
{
connection.ConnectionString = connectionString;
connection.Open();
using (OracleCommand command = new OracleCommand("DBMS_APPLICATION_INFO.SET_CLIENT_INFO", connection))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("input", OracleDbType.Varchar2, "hello", System.Data.ParameterDirection.Input);
command.ExecuteNonQuery();
}
connection.Close();
}
using (OracleConnection connection = new OracleConnection())
{
connection.ConnectionString = connectionString;
connection.Open();
using (OracleCommand command = new OracleCommand("DBMS_APPLICATION_INFO.READ_CLIENT_INFO", connection))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("output", OracleDbType.Varchar2, 4000, "", ParameterDirection.Output);
command.ExecuteNonQuery();
string clientInfo = command.Parameters["output"].Value.ToString();
MessageBox.Show(clientInfo);
}
connection.Close();
}
This code results in a message box showing "hello", although my new session has never set the session variable and must hence not know this value.
So, how do I ensure in Oracle.ManagedDataAccess that my old session gets closed and I get a new session, whenever I want to?
(I know I could keep my old connection open and then open another one, but by opening an additional session every time, my programm would end up with probably hundreds of open sessions for a single user some time, where it should be only one, of course.)
When closing a connection it is by default return to the connection pool.
You can call ClearPool to remove all connections with a specific connection string from the pool.
// Create a new connection object
OracleConnection connNew = new OracleConnection(strConn);
// Clears the pool associated with Connection 'connNew'
// Since the same connection string is set for both the connections,
// connNew and conn, they will be part of the same connection pool.
// We need not do an Open() on the connection object before calling
// ClearPool
OracleConnection.ClearPool (connNew);
See https://docs.oracle.com/database/121/ODPNT/OracleConnectionClass.htm#CHDFJBAF
Related
EDIT: I've just tested it in ASP.NET and it works perfectly fine. So no issue with the connection string or anything. Guess Unity doesn't like this method? Maybe there's some more DLL's I need to copy? Any ideas?
So I'm making a game in Unity and I'm trying to use the System.Data.SqlClient library to connect to some stored procedures I have made for things such as registering a user.
I have copied the System.Data.dll from "C:\Program Files\Unity\Editor\Data\Mono\lib\mono\unity" and that has all worked fine.
I'm currently using this connection string, which works fine on an ASP.NET application but just using a different mdf:
private string connectionString = #"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename='C:\Users\uppy8\Desktop\Computer Science Project\Mining Game\Assets\MineRace.mdf';Integrated Security = True";
The problem occurs when running this code:
using System.Data.SqlClient;
using System.IO;
public void Login()
{
Crypto crypto = new Crypto();
using (SqlConnection conn = new SqlConnection(connectionString))
{
try
{
conn.Open();
} catch (Exception e)
{
Debug.Log(e);
}
SqlCommand command = new SqlCommand("USERS_LOGIN_USER", conn);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#Username", usernameInputField.text));
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
if (crypto.EncryptString(passwordInputField.text) == reader["password"].ToString())
{
UserAccountManager.instance.userInfo = FetchUserInfo((int)reader["id"]);
}
}
}
}
The problem happens on the line "conn.Open()", where Unity gives me the error:
System.Net.Sockets.SocketException: No such host is known.
Furthermore, without the try catch, the error occurs where I create a new SqlDataReader, where I get this issue:
InvalidOperationException: ExecuteReader requires an open connection to continue. This connection is closed.
I understand that this is an issue with the connection, in that it's not running or the connection isn't working properly, however I can't seem to find a solution and I have a sneaky suspicion that it's something to do with Unity not supporting this library.
Some more clarification just before I end off:
The user enters their credentials into the "usernameInputField" and "passwordInputField"
The user presses Login, which runs the "Login" method shown above
The error occurs.
If any more information is required please leave a comment.
Thanks!
What is the scope of connectionString? Do you need to pass the connectionString to the Login() function?
public void Login(string connectionString)
I am a DBA, not a .Net developer, so forgive me if my questions are too basic or if my .Net syntax is wrong.
You can try this
string connectionString = #"Data Source = (localdb)\MSSQLLocalDB; Initial Catalog ='C:\USERS\uppy8\Desktop\Computer Science Project\Mining Game\Assets\MineRace.mdf'; Integrated Security = True; Connect Timeout = 30; Encrypt = False; TrustServerCertificate = True; ApplicationIntent = ReadWrite; MultiSubnetFailover = False"
SqlConnection con = new SqlConnection();
if (con.State==ConnectionState.Open)
{
con.Close();
con.ConnectionString = connectionString;
con.Open();
cmd.Connection = con;
}
else
{
con.ConnectionString = connectionString;
con.Open();
cmd.Connection = con;
}
I am trying to make a simple MS Access Database connection by using the SqlConnection and SqlCommand objects.
As you can see here is how I make the connection:
private SqlConnection GetConnection()
{
String connStr = ConfigurationManager.ConnectionStrings[0].ConnectionString;
SqlConnection conn = new SqlConnection(connStr);
return conn;
}
And before you ask, yes I have tried to move this piece of code to the method that calls it. Didn't change anything. It still reads the connection string wrong.
The connection string looks like this and is located in the App.config file:
<add name="ConnString" connectionString="Server=*.*.*.*;Database=familie;User Id=mfs;Password=********;"/>
But when I get this error:
And look at the connection string object at the time, the string looks like this:
"data source=.\\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true"
I have spent about 2 hours now trying to make this work, going to many different sites to figure out what I did wrong, but I either get information is that is too old, conflicting or deals with connecting to a local database, when this is in fact an external one access through a proxy that was given to me by my client (TrustGate if anyone should ask)
The method that calls GetConnection() looks like this:
public Dictionary<int,String> GetPostNrList()
{
SqlConnection conn = GetConnection();
SqlCommand cmd = new SqlCommand("Execute dbo.HENT_POST_NR_LISTE", conn);
var reader = cmd.ExecuteReader();
Dictionary<int, String> liste = new Dictionary<int, string>();
while (reader.NextResult())
{
int post_nr = (int) reader.GetSqlInt32(0);
String by = reader.GetString(1);
liste.Add(post_nr, by);
}
CloseConnection(conn);
return liste;
}
What exactly am I doing wrong?
The exception message tells you exactly what the problem is - your connection is not open. You just need to open the connection prior to executing a command:
conn.Open();
BTW, a good pattern is to using a using block when dealing with SQL connections, to ensure it gets disposed properly:
using (var conn = GetConnection())
{
using (var comm = xxxxxxx)
{
conn.Open();
using (var rdr = comm.ExecuteReader())
{
// xxxxx
}
}
}
You don't have to specifically close anything - the using pattern does all that for you.
Question:
Why is the following code leaking connections ?
public System.Data.DataTable GetDataTable()
{
System.Data.DataTable dt = new System.Data.DataTable();
string strConnectionString = "Data Source=localhost;Initial Catalog=MyDb;User Id=SomeOne;Password=TopSecret;Persist Security Info=False;MultipleActiveResultSets=False;Packet Size=4096;";
System.Data.SqlClient.SqlConnectionStringBuilder csb = new System.Data.SqlClient.SqlConnectionStringBuilder(strConnectionString);
csb.IntegratedSecurity = true;
string strSQL = "SELECT * FROM T_Benutzergruppen";
using (System.Data.SqlClient.SqlConnection sqlcon = new System.Data.SqlClient.SqlConnection(csb.ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(strSQL, sqlcon))
{
if (sqlcon.State != System.Data.ConnectionState.Open)
{
sqlcon.Open();
}
// First attempt
//System.Data.SqlClient.SqlDataAdapter sqlda = new System.Data.SqlClient.SqlDataAdapter("SELECT * FROM T_Benutzer", sqlcon);
//sqlda.Fill(dt);
cmd.ExecuteNonQuery();
}
if(sqlcon.State != System.Data.ConnectionState.Closed)
sqlcon.Close();
}
//sqlcon.ConnectionString = csb.ConnectionString;
// Second attempt
//System.Data.SqlClient.SqlDataAdapter sqlda = new System.Data.SqlClient.SqlDataAdapter("SELECT * FROM T_Benutzer", csb.ConnectionString);
//sqlda.Fill(dt);
return dt;
}
If I go into SQL-Server activity monitor, I see Session 68
SELECT * FROM T_Benutzergruppen
Additional question:
If question:
If I comment out everything except the ConnectionStringBuilder, and only execute the below code in this function, why does it leak a connection, too ?
// Second attempt
System.Data.SqlClient.SqlDataAdapter sqlda = new System.Data.SqlClient.SqlDataAdapter("SELECT * FROM T_Benutzer", csb.ConnectionString);
sqlda.Fill(dt);
Note:
The executenonquery makes no sense, it's just there for testing purposes.
If I let it run in the debugger, I see that
sqlcon.Close();
get's executed, so the problem is not the
if(sqlcon.State != System.Data.ConnectionState.Closed)
Connection Pooling. Don't worry about it.
This is normal behavior.
http://msdn.microsoft.com/en-us/library/8xx3tyca(v=vs.100).aspx
ADO.Net pools connections so that they can be re-used because they are relatively expensive to create.
Connecting to a database server typically consists of several time-consuming steps. A physical channel such as a socket or a named pipe must be established, the initial handshake with the server must occur, the connection string information must be parsed, the connection must be authenticated by the server, checks must be run for enlisting in the current transaction, and so on.
In practice, most applications use only one or a few different configurations for connections. This means that during application execution, many identical connections will be repeatedly opened and closed. To minimize the cost of opening connections, ADO.NET uses an optimization technique called connection pooling.
http://msdn.microsoft.com/en-us/library/8xx3tyca(v=vs.100).aspx
Also, there is no need to explicitly call .Close(). Your using block will call IDisposable.Dispose(), which will close the connection properly.
I am new to C#. I have a program which reads multiple tables in single database. Suppose if i am reading table A so before reading this I have to connect to database in C#. after this I have to fetch some information from table B. Do I have to give the server info, userid and password again to connect to database?
You can use a single connection for both tables as long as the user has permissions to read from table A and table B.
For example, if you're using SqlCommands and a SqlConnection, set the connection as follows:
SqlConnection connection;
SqlCommand commandA;
SqlCommand commandB;
connection = new SqlConnection("some connection string");
connection.Open();
commandA = new SqlCommand();
commandA.Connection = connection;
commandB = new SqlCommand();
commandB.Connection = connection;
You can then set the CommandType and CommandText on both commandA and commandB as needed. As long as the connection is still open and the user has access to both tables, you'll be set.
We would need to see your code (please mask out your actual user credentials) but the short answer will be yes if you are using a seperate connection to perform the fetch.
If your SqlConnection object has not been disposed or closed you can reuse it on your next SqlCommand
Yes you can. SqlConnection implements IDisposible, so wrap it in a using block.
Psuedocode:
try
{
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
conn.Open();
SqlCommand comm = new SqlCommand(conn);
comm.CommandText = "Select Col1, Col2 From Table1";
SqlCommand comm1 = new SqlCommand(conn);
comm.CommentText = "Select Col1, Col2 From Table2";
//Execute First Command Code
//Execute Second Command Code
} //Connection will be closed and disposed
}
catch (Exception e)
{
//Handle e - Really want to handle specific types of exceptions, like SqlExceptions etc.
}
I have an application that fires a mysql command (query) "show databases", the query works and returns properly but I can't close my connections. The user I used had 24 connections allowed at the same time so the problem popped up further down my program but reducing the allowed connections to 2 shows me that I can't even close the first query (which isn't in a loop). The code is the following:
protected override Dictionary<string, Jerow_class_generator.Database> loadDatabases()
{
MySqlConnection sqlCon = new MySqlConnection(this.ConnectionString);
sqlCon.Open();
MySqlCommand sqlCom = new MySqlCommand();
sqlCom.Connection = sqlCon;
sqlCom.CommandType = CommandType.Text;
sqlCom.CommandText = "show databases;";
MySqlDataReader sqlDR;
sqlDR = sqlCom.ExecuteReader();
Dictionary<string, Jerow_class_generator.Database> databases = new Dictionary<string, Jerow_class_generator.Database>();
string[] systemDatabases = new string[] { "information_schema", "mysql" };
while (sqlDR.Read())
{
string dbName = sqlDR.GetString(0);
if (!systemDatabases.Contains(dbName))
{
databases.Add(sqlDR.GetString(0), new MySQL.Database(dbName, this));
}
}
sqlCom.Dispose();
sqlDR.Close();
sqlCon.Close();
sqlCon.Dispose();
return databases;
}
P.S. The 'New MySQL.Database(dbName, this));' is my owm made class which only stores the DB structure, could be considered irrelevant.
The exact error I get is 'max_user_connections'. on the connection.open line of the next time a query needs to be fired.
Rather than keeping track of all the Open/Close/Dispose calls all over the place, I'd recommend just replacing all of those with using statements. This will make sure the expected scope of each object is clear and that it will be destroyed/disposed upon exiting that scope.
Close() nor using will help alone with your problem because ADO.NET is using its own connection pooling and connections are by default not closed until program is closed. There are few options to solve this, but consider performance implications and is this really desired behavior for your application.
Add ";Pooling=False" to your connection string.
SqlConnection.ClearPool Method
SqlConnection.ClearAllPools Method
For more information read: SQL Server Connection Pooling (ADO.NET)
Along with the using suggestions above, when creating your sqlDR variable you should use the CloseConnection command behavior to close the actual connection if that is your intended action. As noted in the documentation here.
When the command is executed, the associated Connection object is closed when the associated DataReader object is closed.
So your code to instantiate your reader would look like this:
//to instantiate your variable
MySqlDataReader sqlDR;
sqlDR = sqlCom.ExecuteReader(CommandBehavior.CloseConnection);
//closing your datareader reference here will close the connection as well
sqlDR.Close();
If you wrap all your code in a using block using the above method, you don't need any of those Close() or Dispose() methods other than the sqlDR.Close();
when use "using" key word what happen is.when the garbage collector activate it first dispose objects which was declred in using statement.
I recommend using connection pooling in combination with the MySqlHelper class, passing the connection string as the first argument. That allows MySQL to open the connection if necessary, or keep it open according to the pooling cfg, without you having to know about it.
I changed my code to use 1 connection and keep it open and when testing I came across an error that a datareader should be closed. Now since all my queries didn't close the dataReader object (I used dataTable.Load(cmd.ExecuteReader()).) I think the problem might be there.
Keeping 1 open connection worked perfectly so I don't know what caused the not closing problem. I gues it was the dataReader not closing by itself.
Close() will definitely help you close your.
using (MySqlConnection conn = GetConnection())
{
conn.Open();
using (MySqlCommand cmd = conn.CreateCommand())
{
if (conn.State != ConnectionState.Open)
{
conn.Open();
}
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "UserDetail";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
list.Add(new Album()
{
Id = Convert.ToInt32(reader["UId"]),
Name = reader["FirstName"].ToString(),
ArtistName = reader["LastName"].ToString()
});
}
}
}
}
In the above code, you can see one if condition before opening the connection it will help you to reuse your already open connections check below code.
if (conn.State != ConnectionState.Open)
{
conn.Open();
}