C# 使用Dapper中的参数执行存储过程

C# 使用Dapper中的参数执行存储过程,c#,sql,stored-procedures,data-access-layer,dapper,C#,Sql,Stored Procedures,Data Access Layer,Dapper,我正在使用一个带有DAL的微型ORM(谢谢,很棒的项目),由于某种原因,我无法使用输入参数执行存储过程 在一个示例服务中,我有以下代码: public void GetSomething(int somethingId) { IRepository<Something, SomethingEnum> repository = UnitOfWork.GetRepository<Something, SomethingEnum>(); var param =

我正在使用一个带有DAL的微型ORM(谢谢,很棒的项目),由于某种原因,我无法使用输入参数执行存储过程

在一个示例服务中,我有以下代码:

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);

    ...

}
public-void-GetSomething(int-somethingId)
{
IRepository repository=UnitOfWork.GetRepository();
var param=新的动态参数();
param.Add(“@somethingId”,dbType:dbType.Int32,value:somethingId,direction:ParameterDirection.Input);
var result=repository.Exec(somethingeneum.spmystoredprocesdure,param);
...
}
当触发存储过程的执行时,将抛出一个SqlException,说明我需要提供“somethingId”

过程或函数“spMyStoredProcedure”需要未提供的参数“@somethingId”

基于Pencroff的github项目,我的想法与此类似

我是不是遗漏了什么

更新:我实际上是通过SomethingEnum传递commandType:

 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)
    {
    }
}
public类somethingeneum:EnumBase
{
public static readonly somethingeneum spMyStoredProcedure=new somethingeneum(“spMyStoredProcedure”,“[dbo].[spMyStoredProcedure]”,CommandType.StoredProcedure);
public somethingenenum(字符串名称、字符串枚举值、CommandType?cmdType):base(名称、枚举值、cmdType)
{
}
}

您需要告诉它命令类型:确保dapper调用中有一个
commandType:commandType.storedProcess
。否则,它只是执行text命令:

spMyStoredProcedure
(在环境上下文中使用一些未使用的参数)。这是合法的TSQL,在不传递参数的情况下尝试调用
spmystoredprocesdure
——就像将
spmystoredprocesdure
放入SSMS并按f5键一样

此外,如果您的参数是固定的,我建议您只使用:

var param = new { somethingId };
或者干脆将其完全内联:

var result = repository.Exec<Something>(SomethingEnum.spMyStoredProcedure,
    new { somethingId }, commandType: CommandType.StoredProcedure);
var result=repository.Exec(somethingeneum.spmystoredprocesdure,
新的{somethingId},commandType:commandType.StoredProcess);

(注意:如果您的
Exec
方法只处理存储过程,您可以将
commandType
移动到该方法内部,或者将其作为可选参数,默认为
commandType.StoredProcedure

您需要扩展它以支持出站参数和返回结果,但它包含用于创建Dapper动态参数的部分

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;
    }
内部静态bool ExecuteProc(字符串sql,列表参数List=null)
{
尝试
{
使用(SqlConnection conn=newsqlconnection(GetConnectionString()))
{                    
DynamicParameters dp=新的DynamicParameters();
if(paramList!=null)
foreach(参数列表中的SqlParameter sp)
dp.Add(sp.ParameterName、sp.SqlValue、sp.DbType);
conn.Open();
返回conn.Execute(sql、dp、commandType:commandType.StoredProcess)>0;
}
}
捕获(例外e)
{
//伐木
返回false;
}
}
var queryParameters=新的动态参数();
添加(“@parameter1”,参数1的值);
添加(“@parameter2”,参数2的值);
等待db.QueryAsync(
“{NameOfStoredProcedure}”,
查询参数,
commandType:commandType.StoredProcess)

由于这是我的最佳结果,但没有关于带有表值参数的ExecuteOnQuery的答案,下面是代码:

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);
        }
    }
var queryParameters=new DynamicParameters();
Add(“@Param0”,datatable0.AsTableValuedParameter());
Add(“@Param1”,datatable1.AsTableValuedParameter());
var结果=等待执行ESTOREDPROC(“usp_InsertUpdate测试”,查询参数);
专用异步任务ExecuteStoredProc(字符串sqlStatement,DynamicParameters参数)
{
尝试
{
使用(SqlConnection conn=newsqlconnection(connectionString))
{
等待连接OpenAsync();
var affectedRows=wait conn.ExecuteAsync(
sql:sqlStatement,
参数:参数,
commandType:commandType.StoredProcess);
返回Result.Ok(affectedRows);
}
}
捕获(例外e)
{
//伐木
返回结果。失败(例如消息);
}
}

这对我很有用。请注意,执行此操作的方法是异步的,因此使用wait和querysync。还要注意,创建匿名类型是为了方便发送“Id”参数

await dbConnection.QueryAsync<Something>("StoredProcedureNameGoesHere @Id", new { Id = id });
wait dbConnection.QueryAsync(“storedProcedurenMegoeshere@Id”,new{Id=Id});

你好,马克,谢谢你的回复。我实际上是在SomethingEnum上传递commandType。这个问题在某种程度上与我在DynamicParameters上的DAL有关。如果我内联执行它,它就工作了。@antao很好,
Exec
看起来不像是一个简洁的方法。你能告诉我这实际上在哪里变成了一个简洁的调用吗?我实际上使用了这个实现:不知何故,我的服务中有一个DynamicParameters类的错误引用,而存储库并没有很好地处理这个事实。正确设置引用,一切正常。这个问题可以结束了。(编译器(几乎)从未出错!)谢谢@MarcGravel我在dapper中使用存储过程来插入而不是发送单个参数我在Parameters中传递类的对象此方法的返回类型有点混乱,因为如果存储过程调用返回大于0的代码,它将返回true。据我所知,存储过程返回代码通常用于指示过程的成功,其中0表示正常,而>0表示不正常。在这段代码中,如果存储过程返回1,表明调用不正常,C#方法将返回true,这表示
await dbConnection.QueryAsync<Something>("StoredProcedureNameGoesHere @Id", new { Id = id });