Proper way of closing sql connection - without using MARS - c#

My client server is not supporting MARS. So I need to close each sql connection after executing each query. But I have doubt on closing connection when its coming to multiple nested loop query .
My code is
protected void btn_upload_Click(object sender, ImageClickEventArgs e)
{
try
{
SqlConnection con = obj.getcon();
con.Open();
SqlCommand cmd77 = new SqlCommand("select * from emp_details where emp_id='"+emp_id+"'", con);
SqlDataReader dr77 = cmd77.ExecuteReader();
if (dr77.HasRows)//dont insert if employee already exist
{
string query1 = "UPDATE emp_details SET emp_name= #emp_name where emp_id=#emp_id";
SqlCommand cmd = new SqlCommand(query1, con);
cmd.Parameters.Add(new SqlParameter("emp_id", emp_id));
cmd.Parameters.Add(new SqlParameter("emp_name", emp_name))
cmd.ExecuteNonQuery();
}
else
{
insertdataintosql(GetempID,GetempName);
}
con.Close();
}
catch (Exception ex)
{
string ex=ex.Message;
}
}
public void insertdataintosql(string emp_id, string emp_name)
{
SqlConnection con = obj.getcon();
con.Open();
string query = "insert into emp_details(emp_id,emp_name) values(#emp_id,#emp_name)";
SqlCommand cmd = new SqlCommand(query, con);
cmd.Parameters.Add(new SqlParameter("emp_id", emp_id));
cmd.Parameters.Add(new SqlParameter("emp_name", emp_name))
cmd.ExecuteNonQuery();
con.Close();
}
Where should I close the first connection for SqlDataReader (dr77) since it is used in if else loop? If not using MARS , Shall I need to open/close a new connection on update query? So is it necessary to close dr77 to before it?

Related

Getting connection Open when Using a SqlConnection block within Another Block

In the project I call a method to query additional information with a SqlConnection block, but then I validate if exists in a second table using another sqlconnection block, but it is supposed to be disposed (closed) after getting back to the method InsertNewData, but when calling to Open the connection for the Insert, I'm getting the following message:
The connection was not closed. The connection's current state is open.
My code is like this:
public void InsertNewData(string operation)
{
DataTable dt = new DataTable();
try
{
if (operation!= string.Empty)
{
using (SqlConnection oconn = new SqlConnection(myDBone))
{
SqlCommand cmd = new SqlCommand();
SqlDataAdapter da = new SqlDataAdapter();
string query = "SELECT * FROM operations "+
"WHERE idoper=#id";
oconn.Open();
cmd = new SqlCommand(query, oconn);
cmd.Parameters.Add(new SqlParameter("#id", operation.ToString()));
da = new SqlDataAdapter(cmd);
da.Fill(dt);
}
if (dt.Rows.Count > 0)
{
using (SqlConnection con = new SqlConnection(myDBtwo))
{
SqlCommand com = new SqlCommand();
string query= "";
foreach (DataRow x in dt.Rows)
{
if (ValidateData(x) == false)
{
query= "INSERT INTO history(iddata,description, datehist ) "+
" VALUES(#id,#descrip,GETDATE())";
con.Open(); //Here throws the Exception error
com = new SqlCommand(query, con);
com.Parameters.Add(new SqlParameter("#id", x["idoper"].ToString()));
com.Parameters.Add(new SqlParameter("#descrip", x["description"] ));
com.ExecuteNonQuery();
}
}
}
}
}
}
catch (Exception x)
{
throw x;
}
}
public bool ValidateData(DataRow row)
{
bool exists= false;
string operation= row["idoper"].ToString();
string descrip= row["description"].ToString();
if (operation!= string.Empty && descrip!= string.Empty)
{
using (SqlConnection oconn = new SqlConnection(sqlrastreo))
{
SqlCommand cmd = new SqlCommand();
string query = "SELECT COUNT(*) FROM history "+
"WHERE iddata=#id AND description=#descrip";
oconn.Open();
cmd = new SqlCommand(query, oconn);
com.Parameters.Add(new SqlParameter("#id", operation));
com.Parameters.Add(new SqlParameter("#descrip", descrip));
int count = (int) cmd.ExecuteScalar();
if (count > 0)
exists= true;
}// Here it should be Disposed or closed the SqlConnection
}
return exists;
}
What I'm doing wrong, because it's suppose to be closed the other connection and the other hasn't been opened ? or Should I Still call the Close() method for each SqlConnection inside the block Using?
Updated:
I've changed to parameters for best reading code and recommendation syntax.
NOTE
The values and parameters aren't the real ones, my real table descriptions have about 8 fields, but I validate with just two parameters that aren't primary key, but considering that I can't edit the table properties (Have only reading permissions for that database).
Update 2:
Thanks to the recommendation of Sean Lange, it was better and so simple to use a Store Procedure (SP) to validate and insert at the same time, so I do it as follow in code of the process:
public void InsertNewData(string operation)
{
try
{
if(operation == string.Empty)
return;
using(SqlConnection con = new SqlConnection(myDBtwo))
{
con.Open();
var cmd = new SqlCommand("SP_InsertData", con);
cmd.Parameters.Add(new SqlParameter("#id", operation));
cmd.ExecuteNonQuery();
}
}
catch(Exception ex)
{ throw ex; }
}
And then in my SP I insert a select statement of the parameter, to avoid duplicates and also do it in One go:
CREATE PROCEDURE SP_InsertData #id VARCHAR(10)
AS
BEGIN
INSERT INTO History
SELECT O.idoper, O.description
FROM myDBone.dbo.operations O
LEFT JOIN History H
ON H.iddata = O.idoper AND H.description = O.description
WHERE O.idoper=#id AND H.iddata IS NULL
END
Thanks for your support, and hope it helps someone.
First your code is badly written,as they have suggested you don't need to validate,try catch will do it for you.second opening a connection inside a loop ( foreach in your case) will will result to trying to open already open connection. Example here you could do something like
query= "INSERT INTO history(iddata,description, datehist" VALUES(#id,#descrip,GETDATE())";
using (SqlConnection con = new SqlConnection(myDBtwo))
{
con.Open();
SqlCommand com = new SqlCommand(query,con);
foreach (DataRow x in dt.Rows)
{
com.Parameters.Add(new SqlParameter("#id", x["idoper"].ToString()));
com.Parameters.Add(new SqlParameter("#descrip", x["description"] ));
com.ExecuteNonQuery();
}
}
}

ODP.NET Implement Cursor for SELECT statement

How can I implement a simple cursor fetch on a basic SELECT statement like 'SELECT * FROM Employees' using ODP.NET?
So it's quite straightforward.
First create OracleConnection class like this
OracleConnection con = new OracleConnection(ConfigurationManager.ConnectionStrings["connectionstring"].ConnectionString);
con.Open(); //opens connection
Then you define and OracleCommand instance first by passing either raw query/stored procedure as first argument like
So in your particular case it would be OracleCommand cmd = new OracleCommand("SELECT * FROM Employees", con
if (con.State == ConnectionState.Open)
{
using (OracleCommand cmd = new OracleCommand(<query>/<stored proc>, con))
{
cmd.CommandType = CommandType.StoredProcedure; //in case of stored proc
cmd.BindByName = true;
OracleDataReader reader;
try
{
reader = cmd.ExecuteReader();
while(reader.Read())
{
Console.WriteLine("field: {0}", reader.GetDecimal(0));
}
}
catch (OracleException e)
{
foreach (OracleError err in e.Errors)
{
//print errors
}
}
con.Close();
con.Dispose();
}
}
Here is the example http://www.oracle.com/technetwork/articles/dotnet/williams-refcursors-092375.html

What query syntax should I use for inserting records in an Oracle database?

I'm a beginner and trying to create a simple program in C# for inserting and updating records in an Oracle database. I have managed to successfully connect to the database but I'm getting an exception for my SQL statement which states that (?) symbol is not supported. Why am I getting this exception and how can I fix this?
My code is:
private void btnSave_Click(object sender, EventArgs e)
{
OracleConnection con = null;
try
{
con = new OracleConnection();
string constr = "Data source=XE; User ID=cloudester; Password=cloudester123;";
if (con.State != ConnectionState.Open)
{
try
{
con.ConnectionString = constr;
con.Open();
//MessageBox.Show("Successfull connection");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Exception caught");
}
}
if (con.State == ConnectionState.Open)
{
string str = "Insert into EMP_DETAIL(EmpId, Name, Age)";
str += "values (?,?,?)";
OracleCommand cmd = new OracleCommand();
cmd.CommandText = Text;
cmd.Connection = con;
cmd.Parameters.Add(new OracleParameter("EmpId", OracleDbType.Varchar2)).Value = txtEmpId;
cmd.Parameters.Add(new OracleParameter("Name", OracleDbType.Varchar2)).Value = txtName;
cmd.Parameters.Add(new OracleParameter("Age", OracleDbType.Int16)).Value = int.Parse(txtAge.Text);
cmd.ExecuteNonQuery();
}
}
catch { ... }
}
You need to use the named parameter for your command
string str = "Insert into EMP_DETAIL(EmpId, Name, Age) values (:EmpId, :Name, :Age)";
OracleCommand cmd = new OracleCommand();
cmd.CommandText = str; //cmd.CommandText = Text; not sure why did you use Text here
cmd.Connection = con;
cmd.Parameters.Add(new OracleParameter("EmpId", OracleDbType.Varchar2)).Value = txtEmpId;
cmd.Parameters.Add(new OracleParameter("Name", OracleDbType.Varchar2)).Value = txtName;
cmd.Parameters.Add(new OracleParameter("Age", OracleDbType.Int16)).Value = int.Parse(txtAge.Text);
cmd.ExecuteNonQuery();
As agent5566 said, and from OracleCommand.Parameters property;
When using named parameters in an SQL statement called by an
OracleCommand of CommandType.Text, you must precede the parameter name
with a colon (:)
Use them like;
using(var con = new OracleConnection(constr))
using(var cmd = con.CreateCommand())
{
cmd.CommandText = #"Insert into EMP_DETAIL(EmpId, Name, Age)
values (:EmpId, :Name, :Age)";
cmd.Parameters.Add(new OracleParameter("EmpId", OracleDbType.Varchar2)).Value = txtEmpId;
cmd.Parameters.Add(new OracleParameter("Name", OracleDbType.Varchar2)).Value = txtName;
cmd.Parameters.Add(new OracleParameter("Age", OracleDbType.Int16)).Value = int.Parse(txtAge.Text);
con.Open();
cmd.ExecuteNonQuery();
}
By the way, System.Data.OracleClient has been marked as deprecated in .NET 4 version. You might wanna use Oracle Data Provider for .NET instead.
As an alternative, DataDirect and DevArt also have their own oracle providers for .NET.

Working on SQL Queries in C#

Is there a better way of implementing multiple SQL queries? I had tried this; it works fine, but I think it's not efficient.
static void Main(string[] args)
{
SqlConnection con = new SqlConnection();
con.ConnectionString = #"Data Source=(LocalDB)\v11.0;AttachDbFilename=C:\Users\MUHAMMAD\Documents\samEE.mdf;Integrated Security=True;Connect Timeout=30";
SqlCommand cmd = new SqlCommand("Select * from Student", con);
con.Open();
SqlDataReader dr;
dr = cmd.ExecuteReader();
while (dr.Read())
{
Console.WriteLine("Id is:"+dr[0]+" Name is:"+ dr[1]);
}
con.Close();
SqlConnection con2 = new SqlConnection();
con2.ConnectionString = #"Data Source=(LocalDB)\v11.0;AttachDbFilename=C:\Users\MUHAMMAD\Documents\samEE.mdf;Integrated Security=True;Connect Timeout=30";
SqlCommand cmd2 = new SqlCommand("Select Name from Student", con2);
con2.Open();
SqlDataReader dr2;
dr2 = cmd2.ExecuteReader();
while (dr2.Read())
{
Console.WriteLine("Name is :"+ dr2[0]);
}
con2.Close();
Console.ReadKey();
}
Your sample makes no sense. You query two times for the same table. In the first query you get back all the column from the Student table and then you use only the ID and Name fields, in the second one you get back just the student name, but this was already available in the first query
Just one query could be enough (and apply the using statement to properly close and dispose the objects involved)
string conString = ".....";
using(SqlConnection con = new SqlConnection(conString))
using(SqlCommand cmd = new SqlCommand("Select ID, Name from Student", con))
{
con.Open();
using( SqlDataReader dr = cmd.ExecuteReader())
while (dr.Read())
{
Console.WriteLine("Id is:"+dr[0]+" Name is:"+ dr[1]);
}
}
If you want to execute two queries in the same time, you could append the two queries to the same command separating them with a semicolon
using(SqlCommand cmd = new SqlCommand("Select ID, Name from Student;" +
"Select CourseID, CourseName from Course", con))
In this example you get back two set of records, one for the Student table and one for Course table. When you call the ExecuteReader, the readear is positioned on the first result set (the Student list), but you enclose this loop in a do/while block that will control the switch to the second result set (the Course) when the first has been totally read
using(SqlDataReader reader = cmd.ExecuteReader())
{
do
{
// First time reads the student, when finished, the NextResult call switch the reader
// on the second set and then exits (because there are no more result sets)
while(reader.Read())
{
}
}while(reader.NextResult());
Is there a Better way of implementing multiple Queries.
Re-use the connection string
string connString = #"Data Source=(LocalDB)\v11.0;AttachDbFilename=C:\Users\MUHAMMAD\Documents\samEE.mdf;Integrated Security=True;Connect Timeout=30";
use using on connections, commands, and readers:
using SqlConnection con = new SqlConnection(connString))
{
using(SqlCommand cmd = new SqlCommand("Select * from Student", con))
{
....
}
}
Your contrived example pulls the same values from the same table in two separate queries, so I don't know what your real-world example would be to make it better. Why can;t you just re-use the values pulled from the first query?
You already have name in your first query, so why use second query to fetch name.
Few general points :
Acquire connection as late as possible, and, close them early.
Re-usable connection instead of opening a new connection every time a connection request to the database is made by the application.
When you are specifying the connection string, ensure that you specify the IP address of the database server to connect to,
rather than the Database Server’s DNS name.
Credit goes to
static void Main(string[] args)
{
try
{
SqlConnection con = new SqlConnection();
con.ConnectionString = #"Data Source=(LocalDB)\v11.0;AttachDbFilename=C:\Users\MUHAMMAD\Documents\samEE.mdf;Integrated Security=True;Connect Timeout=30";
SqlCommand cmd = new SqlCommand("Select Id,Name from Student", con);
con.Open();
SqlDataReader dr;
dr = cmd.ExecuteReader();
while (dr.Read())
{
Console.WriteLine("Id is:"+dr[0]+" Name is:"+ dr[1]);
}
con.Close();
con.Dispose();
Console.ReadKey();
}
catch (Exception ex)
{
Response.Write("Error: " + ex.Message);
}
finally
{
if(con.State == ConnectionState.Open)
con.Close();
}
}
Also check this whether the ADO.NET DataReader or the DataSet is the better tool.
Try this..
static void Main(string[] args)
{
SqlConnection con = new SqlConnection();
con.ConnectionString = #"Data Source=(LocalDB)\v11.0;AttachDbFilename=C:\Users\MUHAMMAD\Documents\samEE.mdf;Integrated Security=True;Connect Timeout=30";
con.Open();
SqlCommand cmd = new SqlCommand("Select * from Student", con);
SqlDataReader dr;
dr = cmd.ExecuteReader();
while (dr.Read())
{
Console.WriteLine("Id is:"+dr[0]+" Name is:"+ dr[1]);
}
dr.Close();
//con.Close();
//SqlConnection con2 = new SqlConnection();
//con2.ConnectionString = #"Data Source=(LocalDB)\v11.0;AttachDbFilename=C:\Users\MUHAMMAD\Documents\samEE.mdf;Integrated Security=True;Connect Timeout=30";
cmd = new SqlCommand("Select Name from Student", con);
//con2.Open();
SqlDataReader dr2;
dr2 = cmd.ExecuteReader();
while (dr2.Read())
{
Console.WriteLine("Name is :"+ dr2[0]);
}
dr2.Close();
con.Close();
Console.ReadKey();
}
You can pass multiple queries to a single SqlCommand separated by semicolon. Then you can iterate through the data reader like you currently do and at the end request the next query result via dr.NextResult method.
Here's a basic code sample
SqlCommand cmd = new SqlCommand("SELECT Something1 FROM Table1;SELECT Something2 FROM Table2" , con)
con.Open();
SqlDataReader dr = cmd.ExecuteReader();
do {
while (dr.Read())
{
// do stuff with results
}
} while (dr.NextResult())
Outer loop iterates thru query results while inner loop goes thru individual rows of current result.

Trying to use an INSERT method but not working

i'm trying to use an insert method in my studentHelperClass, I am trying to activate it on a button click on my form, I don't know how to make it work with a text box, so if someone could help with that, that would be great.
This is my method:
public static void insertStudent()
{
MySqlConnection conn = connection();
conn.Open();
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = conn;
string myInsertSQL = "INSERT INTO person(personID) ";
cmd.Prepare();
myInsertSQL += "VALUES (#personID)";
cmd.Parameters.AddWithValue("#personID", "123345667788");
prevID(conn, cmd);
}
and this is my form:
private void btnInsert_Click(object sender, EventArgs e)
{
studentHelperClass.insertStudent();
}
EDIT:
private static void prevID(MySqlConnection conn, MySqlCommand cmd)
{
conn.Open();
cmd.ExecuteNonQuery();
long studentNumber = (long)cmd.LastInsertedId;
Console.Write("previous id {0} ", studentNumber);
Console.ReadLine();
conn.Close();
}
Considering the information, assuming that your prevId(conn,cmd) is calling ExecuteNonQuery, you will still need to set the cmd.CommandText to be equal to your myInsertSql (as other answers have pointed out).
To answer your question though,
private void btnInsert_Click(object sender, EventArgs e)
{
studentHelperClass.insertStudent(studentIdTextBox.Text);
}
public static void insertStudent(string studentId)
{
MySqlConnection conn = connection();
conn.Open();
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = conn;
string myInsertSQL = "INSERT INTO person(personID) ";
cmd.Prepare();
myInsertSQL += "VALUES (?personID)";
cmd.CommandText = myInsertSQL;
cmd.Parameters.AddWithValue("?personID", studentId);
prevID(conn, cmd);
}
Ive also assumed your studentId is a string. If the database has it as a bigint, you will have to do the proper long.TryParse() call.
You need to set cmd.CommandText as myInsertSQL
and also need to call cmd.ExecuteNonQuery()
string sql = "INSERT INTO person (personID) VALUES (#personID)";
using (MySqlConnection conn = connection())
using (MySqlCommand cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.AddWithValue("#personID", personID);
conn.Open();
cmd.ExecuteNonQuery();
}
You must assign your string variable, 'myInsertSQL' to cmd.CommandText, and then call, cmd.ExecuteNonQuery();
I.e.
cmd.CommandText = myInsertSQL;
cmd.ExecuteNonQuery();
cmd.Dispose();
Always call 'Dispose();' when finished so the .net Garbage Collection can cleanup and manage resources.
You don't use the myInsertSQL string at all, you just set it. You have to set the string as the command text by cmd.CommandText = myInsertSQL and you have to call the method cmd.ExecuteNonQuery().

Categories