I'll try summarize various pieces of information from other answers and comments.
First, your existing code is open to Sql injections
. This is a very bad thing. To avoid the risk of Sql injection
you shoul use Parametrized queries
. See for instance here.
That means your ExecuteScaler
method should not take a string
as its argument, but instead a SqlCommand
(I have corrected the spelling of scalar):
public string ExecuteScalar(SqlCommand query) { ... }
Your current implementation of ExecuteScaler
is also at risk of leaking SqlConnetions
. If an exception is thrown in this method before the DB.conn.Close()
line, the connection will not be closed. For instance, in the case you described in the question, the following line is the prime suspect:
int val = Convert.ToInt32(cmd.ExecuteScalar());
With your current call to the method, you seem to be fetching something that is a string
from the database. Unless that string is convertible to Int32
, this line will throw an exception, and the connection will not be closed. To fix this, you should at the minimum add a try { ... } finally { ... }
block:
public string ExecuteScalar(SqlCommand query)
{
try
{
DB.EConnection();
query.Connection = DB.conn;
string ret = query.ExecuteScalar().ToString();
return ret;
}
finally
{
if(DB.conn.State == ConnectionState.Open)
DB.conn.Close();
}
}
I would also suggest that you create separate versions of ExecuteScalar
for different expected return types. Perhaps:
public string GetStringScalar(SqlCommand query)
public int GetInt32Scalar(SqlCommand query)
etc.
The calling code then needs to be changed:
string locName = null;
using (SqlCommand locNameCommand = new SqlCommand(@"
select location_name
from wms_storage_bin
where mkey = @mkey
"))
{
locNameCommand.Parameters.AddWithValue("mkey", e.Record["from_bin"]);
locName = GetStringScalar(locNameCommand);
}
newRow["col_frm_bin_id"] = locName;