5

The system I am currently working on uses Stored Procedures for all data access. I'm looking into Dapper at the moment (so far it looks great) but I was wondering if I can use a DynamicParameters object created using a Template but make one of the parameters an output param. For example:

SP:

CREATE PROCEDURE InsertPerson
  @ID int Output,
  @Name varchar(100),
  @DOB DateTime2
AS
--INSERT STATEMENT

SET @ID = SCOPE_IDENTITY()

POCO:

internal class Person
{
  public int ID { get; set; }
  public string Name { get; set; }
  public DateTime DOB { get; set; }
}

Code:

var procParams = new DynamicParameters(person);
connection.Execute("InsertPerson", procParams, commandType: CommandType.StoredProcedure);

// This is where i'm having the issue, can it be done?
person.ID = procParams.Get<int>("ID");

Current I receive an error because the key was not found. Is there a way to get the ID output parameter without manually setting up all of the stored procs parameters?

4

2 回答 2

10

通过快速调整,Add现在替换模板中的值,允许:

public void TestProcWithOutParameter()
{
    connection.Execute(
        @"CREATE PROCEDURE #TestProcWithOutParameter
@ID int output,
@Foo varchar(100),
@Bar int
AS
SET @ID = @Bar + LEN(@Foo)");
    var obj = new
    { // this could be a Person instance etc
        ID = 0,
        Foo = "abc",
        Bar = 4
    };
    var args = new DynamicParameters(obj);
    args.Add("ID", 0, direction: ParameterDirection.Output);
    connection.Execute("#TestProcWithOutParameter", args,
                 commandType: CommandType.StoredProcedure);
    args.Get<int>("ID").IsEqualTo(7);
}

够近了吗?您还可以使用ParameterDirection.ReturnValue, 预先存在的值或新值。请注意,它不会直接更新回原始模板;该值必须从DynamicParameters实例中获取(如图所示)。

于 2011-11-04T20:25:29.227 回答
2

当您使用构造函数DynamicParameters来指定模板对象时,您仍然需要指定这@ID是一个输出参数。首先,通过模板,它将被设置为ParameterDirection.Input. 添加后,它将被覆盖以具有更新的值,然后您可以通过参数名称获取值,如下所示:

procParams.Add("@ID", dbType: DbType.Int32, direction: ParameterDirection.Output);
// ... execute ...
person.ID = procParams.Get<int>("@ID");

除了上面显示的内容之外,我还可以使用您的类和代码来完成这项工作。

编辑:正如评论中所讨论的,存储过程不接受比它声明的更多的参数。因此,另一种方法是放弃存储过程并使用一些内联 SQL。当您使用查询时,Dapper 将忽略任何未在 SQL 语句中指定的参数。这是解决此问题的解决方法:

string sql = "INSERT INTO Person (Name, DOB) VALUES (@Name, @DOB) SELECT SCOPE_IDENTITY()";
decimal id = conn.Query<decimal>(sql, procParams).First();
person.ID = (int)id;

请注意,它SCOPE_IDENTITY()返回一个小数,而不是一个 int。

另一个我认为不理想的想法是修改 Dapper 代码并向类添加一个Remove方法DynamicParameters以删除不需要的参数。但这并没有为您节省太多,因为您仍然会花时间指定要删除所有参数以使存储过程满意。如果您决定实现这一点,请记住在指定要从parameters字典中删除的键时这种情况很重要。

于 2011-11-04T15:04:06.667 回答