I have a stored procedure and I am connecting it to my project and I wanted to know how I can pass the different parameter types in:
Stored procedure:
[dbo].[UploadAssignment]
#studentId int
, #guid uniqueidentifier
, #originalfilename nvarchar(500)
, #uploaddate datetime
In my project:
public virtual IEnumerable<T> GetUploadStudentSubmission<T>(int studentId, .."How should i format the remaining parameters")
{
SqlCommand _command = new SqlCommand("dbo.UploadAssignment");
_command.CommandType = CommandType.StoredProcedure;
_command.Parameters.Add(new SqlParameter { ParameterName = "studentId",SqlDbType = SqlDbType.Int, Value = sectionId});
_command.Parameters.Add(new SqlParameter { ParameterName = "guid", SqlDbType = SqlDbType.Int, Value = guid });
_command.Parameters.Add(new SqlParameter { ParameterName = "originalfilename", SqlDbType = SqlDbType.Int, Value = originalfilename });
_command.Parameters.Add(new SqlParameter { ParameterName = "uploaddate", SqlDbType = SqlDbType.Int, Value = uploaddate });
}
The official documentation states:
The ParameterName is specified in the form #paramname.
So you need to include the # in the parameter name. Other than that, you just need to pass in the relevant parameters just as you would to any other function, like this:
public virtual IEnumerable<T> GetUploadStudentSubmission<T>(
int studentId, Guid guid, string originalfilename, DateTime uploaddate)
{
SqlCommand _command = new SqlCommand("dbo.UploadAssignment");
_command.CommandType = CommandType.StoredProcedure;
_command.Parameters.Add(new SqlParameter { ParameterName = "#studentId",SqlDbType = SqlDbType.Int, Value = sectionId});
_command.Parameters.Add(new SqlParameter { ParameterName = "#guid", SqlDbType = SqlDbType.UniqueIdentifier, Value = guid });
_command.Parameters.Add(new SqlParameter { ParameterName = "#originalfilename", SqlDbType = SqlDbType.NVarChar, Value = originalfilename });
_command.Parameters.Add(new SqlParameter { ParameterName = "#uploaddate", SqlDbType = SqlDbType.DateTime, Value = uploaddate });
}
public virtual IEnumerable<T> GetUploadStudentSubmission<T>(int studentId, Guid guid, string originalfilename, DateTime uploaddate)
{
SqlCommand _command = new SqlCommand("dbo.UploadAssignment");
_command.CommandType = CommandType.StoredProcedure;
_command.Parameters.AddWithValue("#studentId",sectionId);
_command.Parameters.AddWithValue("#guid", guid );
_command.Parameters.AddWithValue("#originalfilename", originalfilename);
_command.Parameters.AddWithValue("#uploaddate", uploaddate);
}
Microsoft also provides the great Enterprise Library which beside other things contains a DataAccess block and handles parameters.
See this answer for more details https://stackoverflow.com/a/3038469/69433
You can also use the following code:
public virtual IEnumerable<T> GetUploadStudentSubmission<T>(int studentId, Guid guid, string originalfilename, DateTime uploaddate)
{
var command = Database.GetStoredProcCommand("[dbo].[UploadAssignment]");
Database.AddInParameter(command, "studentId", DbType.Int32, studentId);
Database.AddInParameter(command, "guid", DbType.Guid, guid);
Database.AddInParameter(command, "originalfilename", DbType.String, originalfilename);
Database.AddInParameter(command, "uploaddate", DbType.DateTime, uploaddate);
var reader = Database.ExecuteReader(command);
commandText = command.CommandAsSql();
reader.Close();
}
Related
I made a generic function to call stored procedures from C#. The code looks like this:
public static void executeStoredProcedure(string SPName, Dictionary<string, object> parameters, string connectionStringName)
{
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString))
{
using (SqlCommand cmd = new SqlCommand(SPName, con))
{
cmd.CommandType = CommandType.StoredProcedure;
if (parameters != null)
{
foreach (KeyValuePair<string, object> kvp in parameters)
cmd.Parameters.Add(new SqlParameter(kvp.Key, kvp.Value));
}
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
}
}
And the code when I use it goes like this:
Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("UserId", UserId);
parameters.Add("UserName", UserName);
GlobalClass.executeStoredProcedure("UpdateUserName", parameters, "userDB");
How do I modify this to be able to work with a stored procedure that has an output parameter, and store the output in a C# variable?
You can use SqlParameter array instead of Dictionary<string, object>. For example
SqlParameter[] parameters = new SqlParameter[]
{
new SqlParameter() {ParameterName = "#UserId", SqlDbType = SqlDbType.NVarChar, Direction = ParameterDirection.Input, Value= UserId},
new SqlParameter() {ParameterName = "#UserName", SqlDbType = SqlDbType.NVarChar, Direction = ParameterDirection.Input, Value = UserName},
new SqlParameter() {ParameterName = "#OutValue", SqlDbType = SqlDbType.Int, Direction = ParameterDirection.Output},
};
GlobalClass.executeStoredProcedure("UpdateUserName", parameters, "userDB");
To store output in C# variable use
int OutVal = Convert.ToInt32(cmd.Parameters["#OutValue"].Value);
This value you can return as the executeStoredProcedure function result or assign this value to an external variable.
To get the output you have to specify an output parameter with the return direction instead of the default input direction.
SqlParameter retVal = new SqlParameter("#retVal", SqlDbType.YOURTYPE);
retVal.Direction = ParameterDirection.ReturnValue;
parameters.Add(parm);
//your code
cmd.ExecuteNonQuery();
object val = retVal.Value;
//your code
Then, pass a bool to your executeStoredProcedure and return an object OR create a new method that has a return value and takes a bool for returning a value.
I have a method similar. I used to List return type and I get sp result with dynamic expandoObject. When I searching this issue, that answer helped me.
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.
in my MVC application there is a method
public void insertAddress(AddressModel address)
{
var connection = OpenConnection();
var command = connection.CreateCommand();
command.CommandText = "insert into Adres (AddressLine_1,AddressLine_2,Postcode,Town,DateMovedIn,Id) values (#AddressLine_1, #AddressLine_2, #Postcode, #Town,#DateMovedIn,#Id)";
AddParameterString(command, "#AddressLine_1", address.AddressLine_1);
AddParameterString(command, "#AddressLine_2", address.AddressLine_2);
AddParameterString(command, "#Postcode", address.Postcode);
AddParameterString(command, "#Town", address.Town);
AddParameterString(command, "#DateMovedIn", address.DateMovedIn.ToString("yyyyMMdd"));
AddParameterInt(command, "#Id", address.Id);
command.ExecuteNonQuery();
}
AddressLine2 in model is not required. When user is not submitting AddressLine2 I get error:
The parameterized query '(#AddressLine_1 nvarchar(3),#AddressLine_2
nvarchar(4000),#Postc' expects the parameter '#AddressLine_2', which
was not supplied.
How can I modify this method to work in both cases - user submitting AddressLine2 and user not submitting AddressLine2?
public void insertAddress(AddressModel address)
{
var connection = OpenConnection();
var command = connection.CreateCommand();
command.CommandText = "insert into Adres (AddressLine_1,AddressLine_2,Postcode,Town,DateMovedIn,Id) values (#AddressLine_1, #AddressLine_2, #Postcode, #Town,#DateMovedIn,#Id)";
command.Parameters.Add(new SqlParameter { ParameterName = "#AddressLine_1", Value = address.AddressLine_1 });
if (address.AddressLine_2 == null)
{
command.Parameters.Add(new SqlParameter { ParameterName = "#AddressLine_2", Value = DBNull.Value });
}
else
{
command.Parameters.Add(new SqlParameter { ParameterName = "#AddressLine_2", Value = address.AddressLine_2 });
}
command.Parameters.Add(new SqlParameter { ParameterName = "#Postcode", Value = address.Postcode });
command.Parameters.Add(new SqlParameter { ParameterName = "#Town", Value = address.Town });
command.Parameters.Add(new SqlParameter { ParameterName = "#DateMovedIn", Value = address.DateMovedIn.ToString("yyyyMMdd") });
command.Parameters.Add(new SqlParameter { ParameterName = "#Id", Value = address.Id });
command.ExecuteNonQuery();
}
This happens when a parameter value is null. To fix it you need to set parameter value to DbNull when the property is null.
void AddParameterString(SqlCommand command, string parameterName, string parameterValue)
{
var param = command.Parameters.Add(parameterName, SqlDbType.NVarChar, 4000);
param.Value = String.IsNullOrEmpty(parameterValue) ? (object) DbNull.Value : (object) parameterValue;
}
You can simply use Null-coalescing operator (??):
AddParameterString(command, "#AddressLine_2", address.AddressLine_2 ?? Convert.DBNull);
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.