I have been writing a lot of open and close connection to a Microsoft SQL Server database. I'm not sure whether it is the latest technique available for .NET. Is there any latest .NET function that I'm missing?
Example code:
protected string InjectUpdateToProductDBString(string Command, TextBox Data, string TBColumn)
{
string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["AuthenticationDBConnectionString"].ConnectionString;
SqlConnection con = new SqlConnection(connectionString);
con.Open();
SqlCommand cmd = new SqlCommand(command, con);
cmd.Parameters.AddWithValue("#" + TBColumn, Data.Text.ToString());
cmd.ExecuteNonQuery();
con.Close();
return "Data successfully updated";
}
Is there any replacement for this fussy code technique? Just a discussion to improve my code technique.
There are other ways to write it and other tools you could use (like Entity Framework).
However, I recommend that you create a static function (or several) for your data access calls.
protected DataTable ExecuteSqlDataReader(string connection, string sqlQuery, SqlParameter[] cmdParams)
{
MySqlConnection con = new MySqlConnection(connection);
MySqlCommand cmd = new MySqlCommand(sqlQuery, con);
cmd.Parameters = cmdParams;
MySqlDataAdapter sda = new MySqlDataAdapter(cmd);
DataTable dt = new DataTable();
sda.Fill(dt);
sda.Command.Close();
return dt;
}
Create methods for Getting a dataTable, One value, ExecuteNonQuery, and even break it further down by abstracting out the SqlCommand creation to it's own method.
In any project, this code should be written only a few times.
Make sure that you enclose your SqlConnection in using statement. It will ensure the connection is closed even if there is an exception. Also, enclose your SqlCommand object in using statement, that will ensure disposal of unmanaged resources.
In your current code snippet if there is an exception at cmd.ExecuteNonQuery(); then your line con.Close would not execute, leaving the connection open.
So your method could be like:
protected string InjectUpdateToProductDBString(string Command, TextBox Data, string TBColumn)
{
string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["AuthenticationDBConnectionString"].ConnectionString;
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
using (SqlCommand cmd = new SqlCommand(command, con))
{
cmd.Parameters.AddWithValue("#" + TBColumn, Data.Text.ToString());
cmd.ExecuteNonQuery();
}
}
return "Data successfully updated";
}
Later you can return a DataTable or List<T> for your returned rows from the query.
If you want to move away from ADO.Net, then you can look into Object-Relation Mapping (ORM), which would provide you objects based on your database and easier way to manage your code base. Entity framework is one of them. You may see https://stackoverflow.com/questions/132676/which-orm-for-net-would-you-recommend
private SqlConnection GetConnection()
{
var con = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["AuthenticationDBConnectionString"].ConnectionString);
con.Open();
return con;
}
protected string InjectUpdateToProductDBString(string Command, TextBox Data, string TBColumn)
{
using (var con = GetConnection())
{
using (var cmd = con.CreateCommand())
{
cmd.Parameters.AddWithValue("#" + TBColumn, Data.Text);
cmd.ExecuteNonQuery();
return "Data Succesfully Updated";
}
}
}
Related
I'm playing around making a POC and I've created the following call.
public string DoStuff()
{
try
{
using (SqlDataAdapter adapter = new SqlDataAdapter())
{
SqlConnection connection = new SqlConnection("Server...");
string command = "insert into Records values (...)";
adapter.InsertCommand = new SqlCommand(command, connection);
}
}
catch (Exception exception)
{
return exception.Message + " " + exception.InnerException;
}
return "WeeHee!";
}
The text I'm seeing returned is the happy one, so I conclude there's no exceptions. Hence, I conclude that the call to the DB is performed as supposed to. However, there's no new lines in the DB being created.
I'm using the same connection string as I have in my config file and the command in pasted in from SQL Manager, where it works.
So my suspicion was that although I create an insert command, I never actually execute it but according to MSDN that's how it's supposed to work.
What stupid thing do I miss here?
You are missing connection.Open(); and adapter.InsertCommand.ExecuteNonQuery();
using (SqlDataAdapter adapter = new SqlDataAdapter())
{
SqlConnection connection = new SqlConnection("Server...");
connection.Open();
string command = "insert into Records values (...)";
adapter.InsertCommand = new SqlCommand(command, connection);
adapter.InsertCommand.ExecuteNonQuery();
}
You should use ExecuteNonQuery instead. Using an SqlDataAdapter for an INSERT query does not make sense.
Also you should Open your connection just before you execute it.
You can:
using(SqlConnection connection = new SqlConnection("Server..."))
{
SqlCommand command = connection.CreateCommand();
command.CommandText = "insert into Records values (...)";
connection.Open();
int craeted = command.ExecuteNonQuery();
}
The example you linked to returned a SQLAdapter for later use.
You don't need one at all:
using (SqlConnection connection = new SqlConnection("Server..."))
{
string command = "insert into Records values (...)";
connection.Open();
var command = new SqlCommand(command, connection);
command.ExecuteNonQuery();
}
Note that there are other execution methods, depending on expected return values and whether you want asynchronous operation: https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand(v=vs.110).aspx
Fill: SelectCommand.Connection property has not been initialized. I have done the coding in button click. Conn is my connection class's object. I have called this connection class in my button click class. Let me know why it shows error? I have already searched answer for this question in Stack overflow and I applied even though it shows the same error. The ddcode.selectedItem.Text is dropdown for select Employee name.
string strQuery = "SELECT MachID, EmpCode, FROM LeaveApply where MachID='" + ddcode.SelectedItem.Text + "'",conn;
SqlCommand cmd = new SqlCommand(strQuery);
SqlDataAdapter sda = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
sda.Fill(dt);
See it is my connection class
public Connection()
{
conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString);
cmd = null;
}
And I have called this connection class in my button click function's class like
Connection conn = new Connection();
There's no point actually creating a SqlCommand object because the SqlDataAdapter will do it for you. In fact, it can even create the SqlConnection object for you. If you need to reuse the connection then do this:
using (var connection = new SqlConnection(connectionString))
using (var adapter = new SqlDataAdapter(query, connection))
{
adapter.SelectCommand.Parameters.AddWithValue(paramName, paramValue);
// ...
}
and, if you don't need to reuse the connection then do this:
using (var adapter = new SqlDataAdapter(query, connectionString))
{
adapter.SelectCommand.Parameters.AddWithValue(paramName, paramValue);
// ...
}
If you really want to create a separate SqlCommand then do this:
using (var connection = new SqlConnection(connectionString))
using (var command = new SqlCommand(query, connection))
using (var adapter = new SqlDataAdapter(command))
{
command.Parameters.AddWithValue(paramName, paramValue);
// ...
}
I would recommend using the CreateCommand factory method of the connection object to create your command, then your command object will correctly use the connection object.
SqlConnection conn = new SqlConnection("ConnectionString");
conn.Open(); // Make sure connection is open.
string strQuery = "SELECT MachID, EmpCode, FROM LeaveApply where MachID='" + selectedItem + "'";
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = strQuery;
SqlDataAdapter sda = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
sda.Fill(dt);
Alternatively you can manually tell the command to use the connection object
cmd.Connection = conn;
It sounds like jmcilhinney has a better answer for your purposes however.
You are missing the connection to your database. The connection will perform the following jobs.
Create a connection to database by using provided connection string.
Open up the connection bridge to transact the data.
Execute the provided query or Stored Procedure.
Fill the data in application's memory
Close the connection bridge to prevent the database.
Use the object of your own connection class.
Try it as follows:
using (Connection Con = new Connection()) {
SqlCommand cmd = new SqlCommand(strQuery);
cmd.Connection = Con;
SqlDataAdapter sda = new SqlDataAdapter(cmd);
try {
Con.Open();
sda.SelectCommand = cmd;
sda.Fill(dt);
Con.Close();
} catch (Exception ex) {
}
When i debug my application, it gives an error that SelectCommand.Connection Property is not been initialized. i dont know what am i doing here wrong :s. I actually want to add a filter over my search on the textchanged event of a textbox.
public class ConnectionClass
{
static SqlConnection cn;
public static SqlConnection Connection()
{
string myConnection = ConfigurationManager.ConnectionStrings["_uniManagementConnectionString1"].ConnectionString;
if (cn != null)
{
cn = new SqlConnection(myConnection);
cn.Open();
}
return cn;
}
}
public class ClassDataManagement
{
SqlConnection cn = ConnectionClass.Connection();
public DataTable GetData(string SQL)
{
SqlCommand cmd = new SqlCommand(SQL, cn);
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
da.Fill(dt);
return dt;
}
}
protected void TextBoxFilterText_TextChanged(object sender, EventArgs e)
{
ClassDataManagement dm = new ClassDataManagement();
string query = "Select CourseCode from _Courses where coursecode like'%" + TextBoxFilterText.Text.TrimEnd() + "%'";
dm.GetData(query);
GridViewCourses.DataBind();
}
That's because your cn variable is null, and not getting initialized. Yet another example why it's a bad idea to initialize and open database connections in a static method.
Try this:
public class ClassDataManagement
{
public DataTable GetData(string SQL)
{
string YourConnectionString = ConfigurationManager.ConnectionStrings["_uniManagementConnectionString1"].ConnectionString;
DataTable dt = new DataTable();
using (SqlConnection cn = new SqlConnection(YourConnectionString))
using (SqlCommand cmd = new SqlCommand(SQL, cn))
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
da.Fill(dt);
}
return dt;
}
}
With the SqlDataAdapter class, you don't need to explicitly call SqlConnection.Open(). The SqlDataAdapter.Fill() method handles all of the connection opening (and closing).
MSDN Reference on SqlDataAdapter.Fill()
As per the above reference, quoted:
The connection object associated with the SELECT statement must be valid, but it does not need to be open. If the connection is closed before Fill is called, it is opened to retrieve data, then closed. If the connection is open before Fill is called, it remains open.
Open connection and close as soon as possible.
public DataTable GetData(string commandString)
{
var result = new DataTable();
using (var cn = new SqlConnection(ConfigurationManager.ConnectionStrings["_uniManagementConnectionString1"].ConnectionString))
using (var cmd = new SqlCommand(commandString, cn))
using (var da = new SqlDataAdapter(cmd))
{
da.Fill(result);
}
return result;
}
Shouldn't that be
if (cn == null)
{
cn = new SqlConnection(myConnection);
cn.Open();
}
Although Sebastian's answer covers a good portion of what's wrong. Here is a more complete list.
You have SQL Injection issues. All queries should be parameterized otherwise you are asking for trouble. Especially when you are directly appending text entered by the user.
You are leaking resources: SqlConnection and SqlCommand. These need to be as close to the code that actually utilizes the connection and command as possible. Trust me, Windows is more than capable of handling all of the open/closing of connections through the build in connection pool. You don't need to maintain this yourself.
The code itself is brittle due to use of embedded SQL in your display layer. By way of example, let's say CourseCode is renamed to CourseId. You will have to search through and modify, potentially, a lot of code files just to make that change. There are multiple ways of limiting exposure to this issue; I'll leave that for you to research.
If I ran across this code in the wild, I would delete the ConnectionClass in its entirety. There is nothing that it is going to do for your that shouldn't be done elsewhere in a more robust manner.
Next I would delete the GetData() method. That is just bad code. You should never accept a full sql string and blindly execute it. There are a lot of security issues just in that one block of code.
Then I would rewrite the ClassDataManagement such that my SQL (if I really wanted it to stay embedded, which I wouldn't because I don't roll that way) was the container for all of my queries. I would have good methods like GetCourseByCourseCode(String courseCode) which would validate that the courseCode is in an expected format then pass it to my sqlcommand object as a parameter to the query.
For bonus points I'd expand on the above by looking at what calls could be better served by cached data. By having them in identified methods, it's much easier to pick and choose what can come from the cache vs what I really need to go across the network and run a query for.
Next, I would make sure that everywhere I made a SQL call, I had my SqlConnection, SqlCommand and readers wrapped in using clauses. It's the best way to ensure that everything is properly closed and disposed of prior to leaving the method. Anything less and you are inviting trouble.
Finally, I would highly consider using Enterprise Library for my data access. It's much better.
Having all given advices, to solve your current problem, you may try this way also:
public class ConnectionClass
{
static SqlConnection cn;
public static SqlConnection Connection()
{
string myConnection = ConfigurationManager.ConnectionStrings["_uniManagementConnectionString1"].ConnectionString;
return new SqlConnection(myConnection);
}
}
public class ClassDataManagement
{
public DataTable GetData(string SQL)
{
using (SqlConnection cn = ConnectionClass.Connection())
{
//SqlCommand cmd = new SqlCommand(SQL, cn);
SqlDataAdapter da = new SqlDataAdapter(SQL,cn);
DataTable dt = new DataTable();
da.Fill(dt);
return dt;
}
}
......
public DataTable GetData()
{
using (System.Data.SqlClient.SqlConnection con = new SqlConnection("YourConnection string"))
{
con.Open();
using (SqlCommand cmd = new SqlCommand())
{
string expression = "Parameter value";
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "Your Stored Procedure";
cmd.Parameters.Add("Your Parameter Name",
SqlDbType.VarChar).Value = expression;
cmd.Connection = con;
using (SqlDataAdapter da = new SqlDataAdapter(SQL, cn))
{
DataTable dt = new DataTable();
da.Fill(dt);
return dt;
}
}
}
}
On my current project, to get a single value (select column from table where id=val), the previous programmer goes through using a datarow, datatable and an sqldatadapter (and of course sqlconnection) just to get that one value.
Is there an easier way to make a simple select query? In php, I can just use mysql_query and then mysql_result and I'm done.
It would be nice if I could just do:
SqlConnection conSql = new SqlConnection(ConnStr);
SomeSqlClass obj = new SomeSqlClass(sql_string, conSql);
conSql.Close();
return obj[0];
Thanks for any tips.
You can skip the DataReader and the DataAdapter and just call ExecuteScalar() on the sql command.
using (SqlConnection conn = new SqlConnection(connString))
{
SqlCommand cmd = new SqlCommand("SELECT * FROM whatever
WHERE id = 5", conn);
try
{
conn.Open();
newID = (int)cmd.ExecuteScalar();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
You are probably looking for SqlCommand and SqlDataReader
Dictionary<int, string> users = new Dictionary<int, string>();
using(SqlConnection connection = new SqlConnection("Your connection string"))
{
string query = "SELECT UserId, UserName FROM Users";
SqlCommand command = new SqlCommand(query, connection);
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
users.Add(reader.GetInt32(0), reader.GetString(1));
}
connection.Close();
}
Actually, there is a method SqlCommand.ExecuteScalar() that will simply return the first field from the first row of the returned results. Just for you.
.NET Framework Class Library
SqlCommand..::.ExecuteScalar Method
Executes the query, and returns the first column of the first row in the result set returned by the query. Additional columns or rows are ignored.
You can do something very similar:
using (SqlConnection conn = new SqlConnection(ConnStr))
using (SqlCommand cmd = new SqlCommand(sql_string, conn))
{
conn.Open();
return cmd.ExecuteScalar();
}
you can use SqlCommands executeScalar function. Please look at the following link
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executescalar.aspx
I have am OLEDB Connection configured in the connection managers and I want to use it in a SCRIPT. The script needs to call a stored proc and then create buffer rows. I have added the connection to the connections available to the script and this is my code.
Boolean fireagain = true;
SqlConnection conn = new SqlConnection();
conn = (SqlConnection)(Connections.Connection
.AcquireConnection(null) as SqlConnection);
SqlCommand cmd = new SqlCommand();
conn.Open();
ComponentMetaData.FireInformation(
0, "Script", "Connection Open", string.Empty, 0, ref fireagain);
cmd.Connection = conn;
cmd.CommandText = "up_FullTextParser_select" ;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("Phrase", DbType.String).Value = Row.Keywords;
cmd.Parameters.AddWithValue("SpecialTerm", DbType.String).Value = "Exact match";
cmd.Parameters.AddWithValue("StopListId", DbType.Int32).Value = 0;
SqlDataReader rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (rdr.Read())
{
TermsBuffer.AddRow();
TermsBuffer.Term = rdr[0].ToString();
}
conn.Close();
Anyway, it seems to fail on the AcquireConnection. Am I converting this wrong? Should I be using a different way to using the connections defined outside the script?.
You cannot cast an OLEDB connection to SqlConnection object. You must use the OleDbConnection object. See the example - http://blogs.msdn.com/b/mattm/archive/2008/08/22/accessing-oledb-connection-managers-in-a-script.aspx
This MSDN example implies that you using AcquireConnection incorrectly.
You need to use a managed connection provider.
If you insist on using an OLEDB connection, you cannot use AcquireConnection but you can extract the connection string and then use it to create an OLEDB connection:
string connstr = Dts.Connections["my_OLEDB_connection"].ConnectionString;
System.Data.OleDb.OleDbConnection objConn = new System.Data.OleDb.OleDbConnection(connstr);
This may not work if the connection string is created via an expression of some sort.
IDTSConnectionManager100 connMgr = this.Connections.ADONetAppStaging ; //this we need to give name in connection manager in script component
SqlConnection myADONETConnection = new SqlConnection();
myADONETConnection = (SqlConnection)(connMgr.AcquireConnection(null));
//Read data from table or view to data table
string query = "Select top 10 * From ##AP_Stagging_Temp_ExportWODuplicates Order by 1,2,3 asc ";
// string query = "Select * From ##AP_Stagging_Temp_For_JLL_ExportWODuplicates order by 1,2,3 asc ";
SqlDataAdapter adapter = new SqlDataAdapter(query, myADONETConnection);
datatable dtExcelData = new datatable();
adapter.Fill(dtExcelData);
myADONETConnection.Close();