Without using Dapper, this code returns the correct result of "true":
using(connection= new SqlConnection(connectionString))
{
using(var cmd = connection.CreateCommand())
{
cmd.CommandText= query;
cmd.CommandType= CommandType.StoredProcedure;
cmd.CommandTimeout = commandTimeout;
var pDeviceId = new SqlParameter
{
ParameterName = "#DeviceId",
DbType = DbType.String,
Size = 150,
Direction = ParameterDirection.Input,
Value = parameter.DeviceId
};
cmd.Parameters.Add(pDeviceId);
var pResponse = new SqlParameter
{
ParameterName = "#Response",
DbType = DbType.Boolean,
Direction = ParameterDirection.Output,
};
cmd.Parameters.Add(pResponse);
await connection.OpenAsync();
int i = cmd.ExecuteNonQuery();
var response = (bool)cmd.Parameters["#Response"].Value;
return response;
}
}
But when using Dapper, I can't get this code to work. It always returns a value of "false":
using (connection = new SqlConnection(connectionString))
{
using(var cmd = connection.CreateCommand())
{
var parameters = new DynamicParameters();
parameters.Add("#DeviceId", parameter.DeviceId);
parameters.Add("#Response", dbType: DbType.Boolean, direction: ParameterDirection.Output);
var reply = (await connection.QueryAsync<bool>(
query,
param: parameters,
commandType: System.Data.CommandType.StoredProcedure).ConfigureAwait(false)).FirstOrDefault();
return reply;
}
}
From here,
var reply = (await connection.QueryAsync<bool>(
query,
param: parameters,
commandType: System.Data.CommandType.StoredProcedure).ConfigureAwait(false)).FirstOrDefault();
this will get the value from the SELECT statement from the stored procedure, but not the value from the Output parameter.
To get the value from the output parameter, you should do as below:
await connection.ExecuteAsync(
query,
param: parameters,
commandType: System.Data.CommandType.StoredProcedure);
var reply = parameters.Get<bool>("#Response");
References
Dapper/ProcedureTest.cs (TestDateTime2LosePrecisionInDynamicParameters method)
Using Parameters With Dapper (Dapper Output Parameter section)
Related
I have created the data source within Visual Studio, I am trying to access a field called Reference No_ by using the Brief Number which is stored as No_.
argclean="AW02464";
string connectionString = "Data Source=ERP-SERVER; Initial Catalog=RMS2015; Integrated Security=True";
SqlConnection con = new SqlConnection(connectionString);
var query = "SELECT [Reference No_] FROM [RMS2015].[dbo].[RMS Live$Artwork Brief] WHERE [No_] = " + argclean + " ";
Above is my code that I have tried but I cant seem to get it to work
It's better to get in the habit of using params in your queries, such as:
var query = "SELECT [Reference No_] FROM [RMS2015].[dbo].[RMS Live$Artwork Brief] WHERE [No_] = #ArtworkNumber;
...and then:
new SqlParameter()
{
ParameterName = "#ArtworkNumber",
SqlDbType = SqlDbType.VarChar,
Value = argclean
}
UPDATE
Here is a general purpose method I use to retreive a DataTable from a query:
public static DataTable ExecuteSQLReturnDataTable(string sql, CommandType cmdType, params SqlParameter[] parameters)
{
using (DataSet ds = new DataSet())
using (SqlConnection connStr = new SqlConnection(YourConnStr))
using (SqlCommand cmd = new SqlCommand(sql, connStr))
{
cmd.CommandType = cmdType;
cmd.CommandTimeout = EXTENDED_TIMEOUT;
foreach (var item in parameters)
{
cmd.Parameters.Add(item);
}
cmd.Connection.Open();
new SqlDataAdapter(cmd).Fill(ds);
return ds.Tables[0];
}
}
It can be called like so:
DataTable dtDeliveryPerformanceResults =
SQLDBHelper.ExecuteSQLReturnDataTable(
PLATYPUS_STOREDPROC,
CommandType.StoredProcedure,
new SqlParameter()
{
ParameterName = "#Unit",
SqlDbType = SqlDbType.VarChar,
Value = unit
},
new SqlParameter()
{
ParameterName = "#BeginDate",
SqlDbType = SqlDbType.DateTime,
Value = _begDate
},
new SqlParameter()
{
ParameterName = "#EndDate",
SqlDbType = SqlDbType.DateTime,
Value = _endDate
},
new SqlParameter()
{
ParameterName = "#PoisonToeLength",
SqlDbType = Convert.ToInt32(SqlDbType.Int),
Value = 42
}
);
The example shows calling a Stored Procedure (a recommended practice), but you can use it with "regular" or "plain vanilla" SQL queries, too.
I have a stored procedure which accepts one string parameter, below is my code
var databaseContext = (DbContext)this.ManagementContext;
databaseContext.Database.Connection.Open();
using (var command = databaseContext.Database.Connection.CreateCommand())
{
command.CommandText = "StoredProcName";
command.CommandType = CommandType.StoredProcedure;
DbParameter param = command.CreateParameter();
param.DbType = DbType.String;
param.Direction = ParameterDirection.Input;
param.Value = "Vikash";
command.Parameters.Add(param);
using (var reader = command.ExecuteReader())
My stored procedure is not getting value in parameter.
You have missed your ParameterName in your code. Try this,
using (var ctx = new StOflowContext())
{
ctx.Database.Connection.Open();
using (var command = ctx.Database.Connection.CreateCommand())
{
command.CommandText = "StoredProcedureName";
command.CommandType = CommandType.StoredProcedure;
DbParameter param = command.CreateParameter();
param.ParameterName = "#paramName";
param.DbType = DbType.String;
param.Direction = ParameterDirection.Input;
param.Value = "Vikash";
command.Parameters.Add(param);
using (var reader = command.ExecuteReader())
{
while(reader.Read())
{
}
}
}
}
I tried this way and it works fine.
var dateParameter = new SqlParameter { ParameterName = "CastID", Value = castMember, DbType = DbType.String, Direction = ParameterDirection.Input };
command.Parameters.Add(dateParameter);
If your stored procedure is named "StoredProcName", and execute with parameter named "Para1".
var executedResult =
((IObjectContextAdapter) this).databaseContext.ExecuteStoreCommand(
"StoredProcName #Para1", "Vikash");
then, you'll get stored procedure result in "executedResult".
I am trying to create a SqlParameterCollection, but gives error while adding some SqlParameter in sp.Add() method.
Please help me how to add parameter and how to pass it to my another function where I declare a SqlConnection and SqlCommand.
SqlParameterCollection sp = null;
sp.Add(new SqlParameter("#CmpyCode", SqlDbType.NVarChar)).Value = CV.Global.CMPYCODE;
sp.Add(new SqlParameter("#Code", SqlDbType.NVarChar)).Value = codeName;
sp.Add(new SqlParameter("#DisplayCode", SqlDbType.NVarChar)).Value = codeName + "-";
sp.Add(new SqlParameter("#TotalDigit", SqlDbType.Int)).Value = CV.Global.PARAMTOTALDIGIT;
insertData("<Sp Name>", sp);
My another function is insertData(...)
internal static int insertData(string spName, SqlParameterCollection sp)
{
int retObj = 0;
using (SqlConnection con = new SqlConnection(CV.Global.CONSTRING))
{
try
{
con.Open();
SqlCommand cmd = new SqlCommand(spName, con);
cmd.CommandType = CommandType.StoredProcedure;
if (sp.Count > 0)
{
foreach (SqlParameter param in sp)
cmd.Parameters.Add(param);
}
retObj = cmd.ExecuteNonQuery();
}
catch (Exception ev)
{
Util.Log(ev);
throw;
}
finally
{
try
{
con.Close();
}
catch (Exception ev) { Util.Log(ev); throw; }
}
}
return retObj;
}
I am trying to create a SqlParameterCollection and passed it to the insertData function. But it throws an error while I am calling sp.Add() method in my first function.
The error is
Object reference not set to an instance of an object
You cannot use any variable like SqlParameterCollection (a reference object) without a call to its constructor (new), but the SqlParameterCollection is an object that cannot be initialized directly with a new. It has no public constructor and can be retrieved only from the property of an existant SqlCommand.
SqlCommand cmd = new SqlCommand(commandText, connection);
SqlParameterCollection sp = cmd.Parameters;
I suggest to change your InsertData method to accept a List<SqlParameter> and let it handle the adding of the parameters to the SqlCommand that executes the command text
List<SqlParameter> sp = new List<SqlParameter>()
{
new SqlParameter() {ParameterName = "#CmpyCode", SqlDbType = SqlDbType.NVarChar, Value= CV.Global.CMPYCODE},
new SqlParameter() {ParameterName = "#Code", SqlDbType = SqlDbType.NVarChar, Value = codeName},
new SqlParameter() {ParameterName = "#DisplayCode", SqlDbType = SqlDbType.NVarChar, Value = codeName + "-"},
new SqlParameter() {ParameterName = "#TotalDigit", SqlDbType = SqlDbType.Int, Value = CV.Global.PARAMTOTALDIGIT}
};
insertData(CV.Sps.SP_INSERT_PARAM_TABLE, sp);
and insertData simply receives an optional list of SqlParameter and add them to the internal SqlCommand parameter collection if needed
internal static int insertData(string spName, List<SqlParameter> sp = null)
{
....
if(sp != null)
cmd.Parameters.AddRange(sp.ToArray());
....
}
Here is a simplified answer. I use this type of thing for a dynamic SQL query with dynamic parameters. Sometimes you don't need all parameters if you are writing a dynamic sqlquery when determining if a variable has a value.
List<SqlParameter> paramList = new List<SqlParameter>();
paramList.Add(new SqlParameter("#StartDate", StartDate));
paramList.Add(new SqlParameter("#EndDate", EndDate));
if (TicketID != "" && TicketID != null && TicketID != "undefined")
{
paramList.Add(new SqlParameter("#TicketID", TicketID));
SQLQuery = SQLQuery + " AND A.TicketID = #TicketID";
}
var Parameters = paramList.ToArray();
List<Report> ReportList = db.Database.SqlQuery<Report>(SQLQuery, Parameters).ToList();
I have a long running stored procedure that returns multiple results.
I'd like to iterate the results asynchronously and grab results as they are ready (AS THEY ARE AVAILABLE).
ExecuteReaderAsync with some WaitOne logic? (never used this so any example is appreciated)
Is this possible?
private IEnumerable<DataTable> validationResultSets(string MOName, DateTime StartDate, DateTime EndDate, string FilePath)
{
DataTable d;
using (SqlConnection conn =
new SqlConnection(connString))
{
conn.Open();
using (cmd = new SqlCommand("dbo.sp_ValidateAcceptanceFile", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter
{
ParameterName = "#MOName",
Value = MOName,
SqlDbType = SqlDbType.VarChar,
Size = 255
});
cmd.Parameters.Add(new SqlParameter
{
ParameterName = "#StartDate",
Value = StartDate,
SqlDbType = SqlDbType.DateTime
});
cmd.Parameters.Add(new SqlParameter
{
ParameterName = "#EndDate",
Value = EndDate,
SqlDbType = SqlDbType.DateTime
});
cmd.Parameters.Add(new SqlParameter
{
ParameterName = "#FilePath",
Value = FilePath,
SqlDbType = SqlDbType.VarChar,
Size = 500
});
//IDataReader rdr = cmd.ExecuteReader();
IDataReader rdr = cmd.BeginExecuteReader(); //??
try
{
do
{
d = new DataTable();
d.Load(rdr);
yield return d;
} while (!rdr.IsClosed);
}
finally
{
rdr.Close();
rdr.Dispose();
}
}
}
}
You are mixing concepts. A procedure returning multiple results is not related in any way to MARS. A procedure returning multiple results can be invoked asynchronously, note that your async call will complete as soon as the first fragment of the result has returned from the server and from there on you read the results just like in the sync code.
How do I get variable #Test that was changed in query?
const string query = #"SET #Test = 2;";
using (var connection = new SqlConnection(conStr))
{
connection.Open();
var command = new SqlCommand(query, connection);
command.Parameters.AddWithValue("#Test", 1);
var r = command.ExecuteReader();
// command.Parameters["#Test"].Value == 1
// r hasn't any variables
}
ADDED:
I've solve this problem withoute creating stored procedure
const string query = #"SET #Test = 2;";
using (var connection = new SqlConnection(conStr))
{
connection.Open();
var command = new SqlCommand(query, connection);
SqlParameter par = command.Parameters.Add("#Test", SqlDbType.NVarChar, 15);
par.Direction = ParameterDirection.Output;
command.ExecuteNonQuery();
// par.Value now contain 2
}
Both ansvers help!
Firstly, in your stored procedure the parameter needs to be marked as OUTPUT
CREATE PROC MyQuery
#Test INT OUTPUT
AS
SET #Test = 2
Then, when constructing the c# code, instead of using AddWithValue, be more explicit in your creation of a SqlParameter, namely marking it as Input/Output.
var command = new SqlCommand("MyQuery", connection);
command.CommandType = CommandType.StoredProcedure;
var param = command.CreateParameter();
param.Name = "#Test";
param.Type = DbType.Int;
param.Direction = ParameterDirection.InputOutput;
param.Value = 1;
Now once you execute your command:
command.ExecuteNonQuery(); // Could also be ExecuteReader, if you have a resultset too!
You can read the value of param, which should have changed to 2
if(param.Value == 2)
{ Console.WriteLine("WooHoo"); }