我可以将 DynamicParameters 与 Template 一起使用并在 dapper 中拥有返回参数吗?

发布于 2024-12-13 14:16:02 字数 805 浏览 1 评论 0原文

我当前正在开发的系统使用存储过程进行所有数据访问。我目前正在研究 Dapper(到目前为止看起来很棒),但我想知道是否可以使用使用模板创建的 DynamicParameters 对象,但将其中一个参数作为输出参数。例如:

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 我收到错误,因为找不到密钥。有没有办法在不手动设置所有存储过程参数的情况下获取ID输出参数?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

°如果伤别离去 2024-12-20 14:16:02

通过快速调整,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 实例中获取(如图所示)。

With a quick tweak, Add now replaces the value from a template, allowing:

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

Is that close enough? You can also use ParameterDirection.ReturnValue, of either a pre-existing value or a new value. Note it does not update directly back into the original template; the value must be fetched from the DynamicParameters instance (as shown).

南汐寒笙箫 2024-12-20 14:16:02

当您使用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() 返回小数,而不是整数。

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

When you use the constructor for DynamicParameters to specify a template object you will still need to specify that @ID is an output parameter. At first, via the template, it will be set to ParameterDirection.Input. Once you add it, it will be overridden to have the updated values, then you can get the value by the parameter name as follows:

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

I was able to get this working and used your classes and code, in addition to what I showed above.

EDIT: as discussed in the comments, the stored procedure doesn't accept more arguments than it has declared. Thus, an alternate approach is to ditch the stored procedure and resort to some inline SQL. When you use a query Dapper will ignore any parameters given to it that aren't specified in the SQL statement. This is a work-around to tackle this issue:

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;

Note that SCOPE_IDENTITY() returns a decimal, not an int.

Another idea, which I think isn't ideal, is to modify the Dapper code and add a Remove method to the DynamicParameters class to remove undesired parameters. This doesn't save you much though since you'll still spend time specifying which parameters to remove all for the sake of making a stored procedure happy. If you decide to implement this remember that case matters when specifying the key to remove from the parameters dictionary.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文