I want to call the stored procedure using C#.
I would like to create a shorthand for the procedure call.
I still do not want to re-define the connection and open it.
How do I create a method - I still did not open connection to the database?
I use the following code:
SqlConnection conn = null;
SqlDataReader rdr = null;
conn = new SqlConnection("");
conn.Open();
SqlCommand cmd = new SqlCommand("Procedure", conn);
cmd.CommandType = CommandType.StoredProcedure;
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
}
I have no idea if I understand what you are asking or not, but do you mean something like:
public static SqlReader executeProcedure(SqlConnection oConn, string commandName, Dictionary<string, object> params)
{
SqlCommand comm = oConn.CreateCommand();
comm.CommandType = CommandType.StoredProcedure;
comm.CommandText = commandName;
if (params != null)
foreach(KeyValuePair<string, object> kvp in params)
comm.Parameters.Add(new SqlParameter(kvp.Key, kvp.Value));
return comm.ExecuteReader();
}
An example of use might be
Dictionary<string, object> paras = new Dictionary<string, object>();
paras.Add("user_name", "Timmy");
paras.Add("date", DateTime.Now);
SqlReader results = executeProcedure(oConn, "sp_add_user", paras);
while (results.Read())
{
//do something with the rows returned
}
results.Close();
FlyingStreudel's answer is good, but I've adapted that code to make this version that demonstrates best practices (links at the bottom.) You can also use Microsoft's Enterprise Library which will give you robust Data Access classes.
private string _connectionString = "yourconnectionstring"; // from web.config, or wherever you store it
public static SqlDataReader executeProcedure(string commandName,
Dictionary<string, object> params)
{
SqlConnection conn = new SqlConnection(_connectionString);
conn.Open();
SqlCommand comm = conn.CreateCommand();
comm.CommandType = CommandType.StoredProcedure;
comm.CommandText = commandName;
if (params != null)
{
foreach(KeyValuePair<string, object> kvp in params)
comm.Parameters.Add(new SqlParameter(kvp.Key, kvp.Value));
}
return comm.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
}
used, like so:
Dictionary<string, object> paras = new Dictionary<string, object>();
paras.Add("user_name", "Timmy");
paras.Add("date", DateTime.Now);
using(SqlDataReader results = executeProcedure("sp_add_user", paras))
{
while (results.Read())
{
//do something with the rows returned
}
}
References:
How Microsoft use Connections in Enterprise Library
Keeping an SqlConnection open is 'foo bar'
Returning a data reader from a class
using (SqlConnection sqlConnection1 = new SqlConnection("Your Connection String")) {
using (SqlCommand cmd = new SqlCommand()) {
Int32 rowsAffected;
cmd.CommandText = "StoredProcedureName";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = sqlConnection1;
sqlConnection1.Open();
rowsAffected = cmd.ExecuteNonQuery();
}}
If you're looking to reuse this kind of code, one possible solution is to wrap this kind of a method (one that executes a stored procedure and returns results) into a generic data access layer of your application. The variations you'd have to consider are for procedures not returning results, or expecting parameters.
You could, for example, wrap this shell code as an ExecuteProcedure() that expects a connection string back to the database.
There are myriad other ways to accomplish this kind of task, so you need to determine what would be the best option suited to your particular requirements.
You can wrap this code and take the procedure as a parameter. Something like this:
public SqlCommand GetData(string procedure)
{
var conn = new SqlConnection(connectionString);
var cmd = new SqlCommand(procedure, conn);
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
return cmd;
}
The only problem with this method is that you are not properly disposing resources and are relying on the caller to do so.
Related
I am trying to run a test query using sql. I know it is a simple concept, but i have tried everything I could find online and the following does not even run. It shows no errors but it does not run.
private static SqlConnection conn = new SqlConnection("<connection string>");
public static void connect()
{
conn.Open();
SqlCommand command = new SqlCommand("spTester 'this is tested'", conn);
command.ExecuteScalar();
conn.Close();
}
It seems that you want something like that:
private static void connect() {
// static SqlConnection conn is a bad idea, local variable is much better
// Do not forget to dispose IDisposable: using(...) {...}
using (SqlConnection conn = new SqlConnection("<connection string>")) {
// Do not forget to dispose IDisposable: using(...) {...}
using (SqlCommand command = new SqlCommand("spTester", conn)) {
// You're executing procedure, not ordinal SQL
command.CommandType = CommandType.StoredProcedure;
// It seems, that you should provide a parameter to your procedure:
//TODO: Change "#ParameterName" to actual one
command.Parameters.Add(new SqlParameter("#ParameterName", "this is tested"));
// You don't need any result value be returned
command.ExecuteNonQuery();
}
}
}
public static void connect()
{
conn.Open();
SqlCommand command = new SqlCommand("spTester 'this is tested'", conn);
command.CommandType = CommandType.StoredProcedure;
SqlDataAdapter da = new SqlDataAdapter(cmd);
conn.Close();
}
try doing this..
as u probably forgot to mention command.CommandType = CommandType.StoredProcedure; line
this is a simple example it will let you get started using SQLCOMMAND
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);
}
}
Try this :
public static void connect()
{
conn.Open();
SqlCommand command = new SqlCommand("spTester", conn);
command.CommandType = CommandType.StoredProcedure;
command.AddWithValue("#Parameter1","this is tested")
SqlDataAdapter da = new SqlDataAdapter(cmd);
conn.Close();
}
I have the following method
public static SqlDataReader MenuDataReader(string url)
{
using (SqlConnection con = new SqlConnection(connectionString))
{
using (SqlCommand cmd = new SqlCommand("spR_GetChildMenus", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#PageUrl", url);
cmd.Parameters.AddWithValue("#MenuId", ParameterDirection.Output);
cmd.Parameters.AddWithValue("#ParentId", ParameterDirection.Output);
cmd.Parameters.AddWithValue("#TitleText", ParameterDirection.Output);
cmd.Parameters.AddWithValue("#ExternalUrl", ParameterDirection.Output);
cmd.Parameters.AddWithValue("#FullUrl", ParameterDirection.Output);
cmd.Parameters.AddWithValue("#ChildCount", ParameterDirection.Output);
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.HasRows)
{
//return reader;
while (reader.Read())
{
return reader;
}
}
}
}
return null;
}
which im calling like this
SqlDataReader reader = MenuDataReader(url);
if (reader.HasRows)
{
while (reader.Read())
{ }}
however im getting the error message
Invalid attempt to call HasRows when reader is closed.
can anyone help me out
thanks
As seen in https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand(v=vs.110).aspx :
public static SqlDataReader ExecuteReader(String connectionString, String commandText,
CommandType commandType, params SqlParameter[] parameters) {
SqlConnection conn = new SqlConnection(connectionString);
using (SqlCommand cmd = new SqlCommand(commandText, conn)) {
cmd.CommandType = commandType;
cmd.Parameters.AddRange(parameters);
conn.Open();
// When using CommandBehavior.CloseConnection, the connection will be closed when the
// IDataReader is closed.
SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
return reader;
}
}
Do you really need the reader, or do you just need some way to iterate over the rows inside it? I suggest an iterator block. You can iterate over your rows inside the source method, and yield each row in turn to the caller.
There is a twist with this technique: because you're yielding the same object with each iteration, there are cases where this can cause a problem, and so you're best off also asking for a delegate to copy the contents of the row somewhere. I also like to abstract this to a generic method that can be used for any query, and use the same delegate technique to handle parameter data, like so:
private IEnumerable<T> GetRows<T>(string sql, Action<SqlParameterCollection> addParameters, Func<IDataRecord, T> copyRow)
{
using (var cn = new SqlConnection("Connection string here"))
using (var cmd = new SqlCommand(sql, cn)
{
cmd.CommandType = CommandType.StoredProcedure;
addParameters(cmd.Parameters);
cn.Open();
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
yield return copyRow(rdr);
}
rdr.Close();
}
}
}
public IEnumerable<MenuItem> GetChildMenus(string url)
{
return GetRows<MenuItem>("spR_GetChildMenus", p =>
{
//these lines are copied from your question, but they're almost certainly wrong
p.AddWithValue("#PageUrl", url);
p.AddWithValue("#MenuId", ParameterDirection.Output);
p.AddWithValue("#ParentId", ParameterDirection.Output);
p.AddWithValue("#TitleText", ParameterDirection.Output);
p.AddWithValue("#ExternalUrl", ParameterDirection.Output);
p.AddWithValue("#FullUrl", ParameterDirection.Output);
p.AddWithValue("#ChildCount", ParameterDirection.Output);
}, r =>
{
return new MenuItem( ... );
}
}
I would not return the reader - the Dispose of your connection and command are closing the connection. I would instead return a representative model of your data.
When you return inside the using statement the code calls Dispose on the SqlConnection. This closes the DataReader, causing the error.
Triggered by a question under Danan's answer, here is a solution based on abstractions. Additionally, it uses good practices like using declarations, async programming (with cancellation tokens omitted for brevity), and proper object disposal (especially with regards to the connection).
// Example invocation
public async Task DemonstrateUsage()
{
var query = #"SELECT * FROM Order WHERE Id = #Id;";
var parameters = new Dictionary<string, object>()
{
["#Id"] = 1,
};
// Caller disposes the reader, which disposes the connection too
await using var reader = await this.ExecuteReader(this.CreateConnection, query, parameters);
while (await reader.ReadAsync())
Console.Log("And another row!");
}
// Concrete implementation of how we produce connections
private DbConnection CreateConnection()
{
return new SqlConnection("ConnectionString");
}
// Fully abstract solution
private async Task<DbDataReader> ExecuteReader(Func<DbConnection> connectionFactory,
string query, IReadOnlyDictionary<string, object> parameters,
CommandType commandType = CommandType.Text)
{
var connection = connectionFactory();
try
{
await using var command = connection.CreateCommand();
command.CommandType = commandType;
command.CommandText = query;
foreach (var pair in parameters)
{
var parameter = command.CreateParameter();
parameter.ParameterName = pair.Key;
parameter.Value = pair.Value;
command.Parameters.Add(parameter);
}
await connection.OpenAsync();
return await command.ExecuteReaderAsync(CommandBehavior.CloseConnection);
}
catch
{
// We have failed to return a disposable reader that can close the connection
// We must clean up by ourselves
await connection.DisposeAsync();
throw;
}
}
I get query result from SQL Server with dynamic number of columns with variable column names.
How can I transform the result from datareader into generic list List ?
public ? getItems(string orderId)
{
SqlConnection sqlConn = new SqlConnection(conn);
SqlCommand command = new SqlCommand();
SqlDataReader reader;
try
{
sqlConn.Open();
command.Connection = sqlConn;
command.CommandText = "usp_get_orders";
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#Id", orderId)));
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
?
}
reader.Close();
}
catch (Exception exp)
{
}
finally
{
command.Dispose();
command1.Dispose();
sqlConn.Close();
sqlConn.Dispose();
}
return ?;
}
If you resulting object is completely dynamic you could use a dictionary instead of a strongly typed object. Or, if you want at least an object, go with dynamic objects. Either use the dynamic keyword and a List<dynamic> or use DynamicObject.
The difference to a dictionary is not that big though...
Something like this could do it:
SqlDataReader reader = command.ExecuteReader();
var listOfValues = new Dictionary<string, object>();
while (reader.Read())
{
for(int i = 0; i <reader.FieldCount;i++)
{
listOfValues.Add(reader.GetName(i), reader.GetValue(i));
}
}
I wanna to know exactly how we do these thing on C# .NET 4.0 Form Application:
Declaring SqlCeParameterCollection Object
Adding Parameters to the collection
Add the Collection to the Command
Here are samples of my current code:
Declaring & Adding
SqlCeParameterCollection Parameters = new SqlCeCommand().Parameters;
Parameters.Add("username", Username);
Parameters.Add("password", Password);
Now how to add this collection at once to the command?
Thanks
Try this:
string query = "...(whatever you need).....";
using(SqlCeConnection conn = new SqlCeConnection(connectionString))
using(SqlCeCommand cmd = new SqlCeCommand(query, conn))
{
// just add parameters directly to SqlCeCommand object ....
cmd.Parameters.Add("username", Username);
cmd.Parameters.Add("password", Password);
conn.Open();
cmd.ExecuteNonQuery(); // or whatever you need to do
conn.Close();
}
If you must set up your parameters separately, up front, then you need to do something like this (since you cannot directly use SqlCeParameterCollection):
List<SqlCeParameters> parameters = new List<SqlCeParameters>();
parameters.Add(new SqlCeParameter(.....));
parameters.Add(new SqlCeParameter(.....));
string query = "...(whatever you need).....";
using(SqlCeConnection conn = new SqlCeConnection(connectionString))
using(SqlCeCommand cmd = new SqlCeCommand(query, conn))
{
// add all parameters from the list - casting to an array
cmd.Parameters.AddRange(parameters.ToArray());
conn.Open();
cmd.ExecuteNonQuery(); // or whatever you need to do
conn.Close();
}
SqlCeCommand.Parameters is read only, so you won't be able to assign a new SqlParametersCollection directly to this property.
You typically want to use the CreateCommand factory method on SqlCeConnection to create the command (as it will link the connection for you).
Then you use the command.Parameters directly:
SqlCeCommand cmd = con.CreateCommand();
// cmd.CommandType = ...; cmd.CommandText = ...
cmd.Parameters.Add("username", Username);
cmd.Parameters.Add("password", Password);
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