I'm using Dapper (thanks Sam, great project.) a micro ORM with a DAL and by some reason I'm not able to execute stored procedures with input parameters.
In a example service I've the following code:
public void GetSomething(int somethingId) { IRepository<Something, SomethingEnum> repository = UnitOfWork.GetRepository<Something, SomethingEnum>(); var param = new DynamicParameters(); param.Add("@somethingId", dbType: DbType.Int32, value:somethingId, direction: ParameterDirection.Input); var result = repository.Exec<Something>(SomethingEnum.spMyStoredProcedure, param); ... }
When the execution of the stored procedure is triggered a SqlException is thrown stating that I need to provide the 'somethingId'
Procedure or function 'spMyStoredProcedure' expects parameter '@somethingId', which was not supplied.
My DAL is similar based on this github project of Pencroff.
Am I missing something here?
Update: I am actually passing the commandType via the SomethingEnum:
public class SomethingEnum : EnumBase<SomethingEnum, string> { public static readonly SomethingEnum spMyStoredProcedure = new SomethingEnum("spMyStoredProcedure", "[dbo].[spMyStoredProcedure]", CommandType.StoredProcedure); public SomethingEnum(string Name, string EnumValue, CommandType? cmdType): base(Name, EnumValue, cmdType) { } }
5 Answers
You need to tell it the command type: make sure there's a commandType: CommandType.StoredProcedure
in the dapper call. Otherwise, it is simply executing the text command:
spMyStoredProcedure
(with some unused parameters in the ambient context). This is legal TSQL, and attempts to call spMyStoredProcedure
without passing parameters - the same as if you put spMyStoredProcedure
into SSMS and press f5.
Also, if your parameters are fixed, I would actually suggest just using:
var param = new { somethingId };
or even just inline it completely:
var result = repository.Exec<Something>(SomethingEnum.spMyStoredProcedure, new { somethingId }, commandType: CommandType.StoredProcedure);
(note: if your Exec<T>
method only ever handles stored procedures, you could move the commandType
internal to the method - or you could make it an optional parameter that defaults to CommandType.StoredProcedure
)
var queryParameters = new DynamicParameters(); queryParameters.Add("@parameter1", valueOfparameter1); queryParameters.Add("@parameter2", valueOfparameter2); await db.QueryAsync<YourReturnType>( "{NameOfStoredProcedure}", queryParameters, commandType: CommandType.StoredProcedure)
1Since this was the top result for me, but there were no answers that deal with ExecuteNonQuery with table valued parameters, here is the code for that:
var queryParameters = new DynamicParameters(); queryParameters.Add("@Param0", datatable0.AsTableValuedParameter()); queryParameters.Add("@Param1", datatable1.AsTableValuedParameter()); var result = await ExecuteStoredProc("usp_InsertUpdateTest", queryParameters); private async Task<Result<int>> ExecuteStoredProc(string sqlStatement, DynamicParameters parameters) { try { using (SqlConnection conn = new SqlConnection(connectionString)) { await conn.OpenAsync(); var affectedRows = await conn.ExecuteAsync( sql: sqlStatement, param: parameters, commandType: CommandType.StoredProcedure); return Result.Ok(affectedRows); } } catch (Exception e) { //do logging return Result.Fail<int>(e.Message); } }
2You'll need to extend it to support outbound parameters and returning results, but it contains the portion for creating the Dapper dynamic parameters.
internal static bool ExecuteProc(string sql, List<SqlParameter> paramList = null) { try { using (SqlConnection conn = new SqlConnection (GetConnectionString())) { DynamicParameters dp = new DynamicParameters(); if(paramList != null) foreach (SqlParameter sp in paramList) dp.Add(sp.ParameterName, sp.SqlValue, sp.DbType); conn.Open(); return conn.Execute(sql, dp, commandType: CommandType.StoredProcedure) > 0; } } catch (Exception e) { //do logging return false; }
}
2This works for me. Note that the method doing this is async, hence the await and QueryAsync. Also notice that an anonymous type is created to facilitate the 'Id' parameter being sent.
await dbConnection.QueryAsync<Something>("StoredProcedureNameGoesHere @Id", new { Id = id });
ncG1vNJzZmirpJawrLvVnqmfpJ%2Bse6S7zGiorp2jqbawutJoaWptaW2BdIOOnq%2Bem6Wpsm6%2F06ipnpxdpb%2Bwr8SdrKudXax6sa3RmqSerJWnwG61zWabmqigmr8%3D