Question about SQL connection and statement in C# - c#

I currently have my SQL statements like this in my C# program.
SqlConnection connection = DataBase.GetConnection();
string deleteStatement = "DELETE FROM People WHERE ID = #ID";
SqlCommand deleteCommand = new SqlCommand(deleteStatement, connection);
deleteCommand.Parameters.AddWithValue("#ID", Id);
try
{
connection.Open();
deleteCommand.ExecuteNonQuery();
}
catch (SqlException ex)
{
throw ex;
}
finally
{
connection.Close();
}
But visual studio 2019 is suggesting to use a using statement instead. Is there any benefit to using ether or?

In addition to the accepted answer:
You could/should dispose SqlCommand as well and using will handle it.
using (var connection = DataBase.GetConnection())
using (var command = connection.CreateCommand())
{
command.CommandText = "DELETE FROM People WHERE ID = #ID";
var parameter = new SqlParameter
{
ParameterName = "#ID",
SqlDbType = SqlDbType.Int,
Value = Id
};
command.Parameters.Add(parameter);
connection.Open();
command.ExecuteNonQuery();
}

using will automatically dispose of the connection (which also closes the connection).

Related

I didn't get error when try to connect SQL Server

I have a Virtual Machine in Windows Azure with SQL Server 2016. This VM has a firewall with Azure, where I allow the IP to connect to the server. And also my project is an ASP.NET Web API 2 with ADO.NET for Data Access Layer.
The thing is all set; everything is working fine (Good!). But If I try to connect from another place with an IP that is not added to the firewall rules, I don't get any error, only still to try to execute the command. Normally if I use the SQL Managment I get an error.
This is my parameter in my connection string
Server=vm.XXXXXX.azure.com;Database={database};User ID={userid};Password={password};Encrypt=True;TrustServerCertificate=True;Connection Timeout=300;ConnectRetryCount=4;ConnectRetryInterval=1
So, this is extract code that I executed:
using (SqlConnection dbConnection = new SqlConnection(myCString))
{
using (SqlCommand dbCommand = new SqlCommand())
{
string queryString;
queryString = "SELECT * FROM table WHERE (ID = #ID) ";
dbCommand.Parameters.Add(Utilities.GetSQLParameter("ID", 1234, SqlDbType.VarChar));
dbCommand.CommandText = queryString;
dbCommand.Connection = dbConnection;
dbConnection.Open();
using (SqlDataReader dr = dbCommand.ExecuteReader())
{
if (dr.Read())
{
Value = dr[Field].ToString();
}
else
{
Value = "";
}
}
}
}
In summary, I want to get the error if I cannot find the VM because the firewall is blocking the access.
The connection failure occurs at dbConnection.Open.
Wrap your code in atry/catch block and treat the error if it occurs.
A list of available catchable exceptions can be found at https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.open(v=vs.110).aspx
try
{
dbConnection.Open();
using (SqlDataReader dr = dbCommand.ExecuteReader())
{
if (dr.Read())
{
Value = dr[Field].ToString();
}
else
{
Value = "";
}
}
}
catch(Exception ex)
{
//Do some treatment
}
finally
{
//If connection has been opened, close it.
if(dbConnection.ConnectionState == ConnectionState.Open)
{
dbConnection.Close();
}
}
I will recommend you use USING clear all your "managed resources"
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement
using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["ConnStringName"].ToString()))
using (SqlCommand mySqlCommand = new SqlCommand())
{
try
{
conn.Open();
mySqlCommand.Connection = conn;
mySqlCommand.CommandType = CommandType.StoredProcedure;
mySqlCommand.CommandText = "getCities";
mySqlCommand.CommandTimeout = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["ConnectionTimeout"].ToString());
mySqlCommand.Parameters.Add("#param", SqlDbType.VarChar).Value = param;
da.SelectCommand = mySqlCommand;
da.Fill(ds, "cities");
}
catch (Exception ex)
{
// LOG HERE the errors
}
} // end using

How to actually execute a command?

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

How to save the result of a SQL query in a variable in c#?

I want to try to save the result of this query (I want to get the value of the primary key) into a variable in c# of a MDB database but I don't know how I can do it:
SELECT ##identity FROM Table
I've tried this but it doesn't work:
int variable;
variable = cmd.CommandText("SELECT ##IDENTITY FROM TABLE");
PD: It isn't all the code, I have a problem only with this part.
You can use this snippet:
SqlCommand command = new SqlCommand(
"SELECT ##IDENTITY FROM TABLE",
connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
Console.WriteLine("{0}\t{1}", reader.GetInt32(0),
reader.GetString(1));
}
}
Is it complete code? You just created command object, but didn't open the connection and did not run the command.
using (SqlConnection conn = new SqlConnection(connString))
{
SqlCommand cmd = new SqlCommand("SELECT ##IDENTITY FROM TABLE", conn);
try
{
conn.Open();
newID = (int)cmd.ExecuteScalar();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

No value was given for one or more required parameters

for (int i = 0; i < dtExcel.Rows.Count; i++)
{
using (var conexao = Conexao())
{
conexao.Open();
string rotaloja = Convert.ToString(dtExcel.Rows[i][1]) + Convert.ToString(dtExcel.Rows[i][0]);
string bn = "select * from Emb where ROTALOJ= #rotaloja";
OleDbCommand cmd1 = new OleDbCommand(bn, conexao);
cmd1.Parameters.AddWithValue("#rotaloja", rotaloja);
using (OleDbCommand Queryyy = new OleDbCommand(bn, conexao))
{
using (OleDbDataReader drr = Queryyy.ExecuteReader())
{
if (drr.Read())
{
try
{
string cmdText = "UPDATE Emb SET ROTA=#p0, LOJA=#p1, QTDEEMBAL=#p2 where ROTALOJ= #rotaloja";
conexao.Open();
OleDbCommand cmd = new OleDbCommand(cmdText, conexao);
cmd.Parameters.AddWithValue("#p0", dtExcel.Rows[i][1]);
cmd.Parameters.AddWithValue("#p1", dtExcel.Rows[i][0]);
cmd.Parameters.AddWithValue("#p2", dtExcel.Rows[i][2]);
cmd.ExecuteNonQuery();
}
catch (OleDbException ex)
{
MessageBox.Show("Error" + ex);
}
}
else
{
try
{
string cmdText = "INSERT INTO Emb (ROTALOJ , ROTA, LOJA, QTDEEMBAL) VALUES (#rotaloja,#p0,#p1,#p2)";
OleDbCommand cmd = new OleDbCommand(cmdText, conexao);
cmd.Parameters.AddWithValue("#p0", dtExcel.Rows[i][1]);
cmd.Parameters.AddWithValue("#p1", dtExcel.Rows[i][0]);
cmd.Parameters.AddWithValue("#p2", dtExcel.Rows[i][2]);
//////////////////////////////////////////////////////////////////////////////////////////////
cmd.ExecuteNonQuery();
}
catch (OleDbException ex)
{
MessageBox.Show("Error" + ex);
}
}
}
}
}
}
I am doing import excel to database more when he does select to see if you have the information in the database is giving error can be? for those who help me thank you
Img : http://i.stack.imgur.com/qxQDm.png
You created a new query Queryyy and assumed that the parameters attached with previous query cmd1 would be available with your command string bn. You need to add parameter to your query Queryyy
using (OleDbCommand Queryyy = new OleDbCommand(bn, conexao))
{
Query.Parameters.AddWithValue("#rotaloja", rotaloja); //here
using (OleDbDataReader drr = Queryyy.ExecuteReader())
//.......rest of your code
}
Consider using helpful variable names.
In your current code, you added parameter to a cmd1 which is independent of Queryyy. In your new query Queryyy, you are using command text which requires a parameter and since you are not passing it, you are getting the exception.
Take a look at : OleDbCommand.Parameters Property, You may have to pass the parameter with ?, since it doesn't seem to support named parameters.
The OLE DB .NET Provider does not support named parameters for passing
parameters to an SQL statement or a stored procedure called by an
OleDbCommand when CommandType is set to Text. In this case, the
question mark (?) placeholder must be used.
You're not setting the value of #rotaloja in this query:
"UPDATE Emb SET ROTA=#p0, LOJA=#p1, QTDEEMBAL=#p2 where ROTALOJ= #rotaloja"
OleDBCommand does not support names parameters. Replace your parameters with ? in each SQL statement and add the parameters in the order that they appear in the query.

SQL query to scalar result in C#

In some programming contexts getting a scalar value from a sql query is easy:
RowCount = Connection.Execute("SELECT Count(*) FROM TableA").Fields(0).Value
In C#, given a SqlConnection variable conn that is already open, is there a simpler way to do this same thing without laboriously creating a SqlCommand, a DataReader, and all in all taking about 5 lines to do the job?
SqlCommand has an ExecuteScalar method that does what you want.
cmd.CommandText = "SELECT COUNT(*) FROM dbo.region";
Int32 count = (Int32) cmd.ExecuteScalar();
If you can use LINQ2SQL (or EntityFramework) you can simplify the actual query asking to
using (var context = new MyDbContext("connectionString"))
{
var rowCount = context.TableAs.Count();
}
If LINQ2SQL is an option that has lots of other benefits too compared to manually creating all SqlCommands, etc.
There is ExecuteScalar which saves you at least from the DataReader:
static public int AddProductCategory(string newName, string connString)
{
Int32 newProdID = 0;
string sql =
"INSERT INTO Production.ProductCategory (Name) VALUES (#Name); "
+ "SELECT CAST(scope_identity() AS int)";
using (SqlConnection conn = new SqlConnection(connString))
{
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.Add("#Name", SqlDbType.VarChar);
cmd.Parameters["#name"].Value = newName;
try
{
conn.Open();
newProdID = (Int32)cmd.ExecuteScalar();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
return (int)newProdID;
}
(Example taken from this MSDN documentation article)
You do not need a DataReader. This example pulls back the scalar value:
Object result;
using (SqlConnection con = new SqlConnection(ConnectionString)) {
con.Open();
using (SqlCommand cmd = new SqlCommand(SQLStoredProcName, con)) {
result = cmd.ExecuteScalar();
}
}
Investigate Command.ExecuteScalar:
using(var connection = new SqlConnection(myConnectionString))
{
connection.Open();
using(var command = connection.CreateCommand())
{
command.CommandType = CommandType.Text;
command.CommandText = mySql;
var result = (int)command.ExecuteScalar();
}
}
If you're feeling really lazy, encapsulate it all in an extension method, like we do.
EDIT: As requested, an extension method:
public static T ExecuteScalar<T> (this SqlConnection connection, string sql)
{
if (connection == null)
{
throw new ArgumentNullException("connection");
}
if (string.IsNullOrEmpty(sql))
{
throw new ArgumentNullException("sql");
}
using(var command = connection.CreateCommand())
{
command.CommandText = sql;
command.CommandType = CommandType.Text;
return (T)command.ExecuteScalar();
}
}
Note, this version assumes you've properly built the SQL beforehand. I'd probably create a separate overload of this extension method that took two parameters: the stored procedure name and a List. That way, you could protect yourself against unwanted SQL injection attacks.

Categories

Resources