简体   繁体   English

如何使用 Dapper 从查询中获取返回值?

[英]How to get return value from query with Dapper?

I'm trying to get a return value from an insert query using Dapper.我正在尝试使用 Dapper 从插入查询中获取返回值。

Here's how I try to make it work:这是我尝试使其工作的方法:

// the query with a "returning" statement
// note : I have a trigger that sets the Id to a new value using the generator IF Id is null...
string SQL = "UPDATE OR INSERT INTO \"MyTable\" (\"Id\", \"Name\") " + "VALUES (@Id, @Name) RETURNING \"Id\"";
using (var conn = new FbConnection(MyConnectionString)) {
    var parameters = new DynamicParameters();
    parameters.Add("Id", null, System.Data.DbType.Int32);
    parameters.Add("Name", "newName", System.Data.DbType.String);
    // --- also add the returned parameters
    parameters.Add("retval", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue);
    // execute the query with Dapper....
    conn.Execute(SQL, parameters);
    // expecting the new ID here but it is ALWAYS null....!!!
    var newId = parameters.Get<object>("retval"); 
}

Now to make sure my query is ok and not the source of the problem here, I implemented a similar code with my actual connector (Firebird in this case), as follows:现在,为了确保我的查询没有问题,而不是问题的根源,我使用我的实际连接器(在本例中为 Firebird)实现了类似的代码,如下所示:

using (var conn = new FbConnection(MyConnectionString)) {
    FbCommand cmd = new FbCommand(SQL, conn);
    cmd.Parameters.Add("Id", null);
    cmd.Parameters.Add("Name", "newName");
    FbParameter pRet = cmd.Parameters.Add("retval", FbDbType.Integer);
    pRet.Direction = ParameterDirection.ReturnValue;
    conn.Open();
    cmd.ExecuteNonQuery();
    // => the new value is NOT null here, it returns the correct id!!
    var newId = Convert.ToInt32(pRet.Value);
    conn.Close();
}

What is my mistake in the Dapper code?我在 Dapper 代码中的错误是什么? Why is one version OK and NOT the other?为什么一个版本可以,而另一个版本不行? I've read that Dapper executes ExecuteNonQuery() so I'm not expecting this to be the cause.我读过 Dapper 执行 ExecuteNonQuery() 所以我不希望这是原因。

The returning clause acts like select , in that it returns data in a results grid. returning子句的作用类似于select ,因为它在结果网格中返回数据。 As such, your query should be executed as a query.因此,您的查询应作为查询执行。 This also has the advantage that it significantly simplifies the calling code:这还有一个优点,它显着简化了调用代码:

var newId = conn.QuerySingle<int>(SQL, new { Id = (int?)null, Name = "newName" });

If you need additional fields, this can be extended to use a custom return type that matches the columns coming back, or a value-tuple.如果您需要其他字段,可以扩展为使用与返回的列或值元组匹配的自定义返回类型。 For example:例如:

var row = conn.QuerySingle<MyTable>(SQL, new { Id = (int?)null, Name = "newName" });

or或者

var row = conn.QuerySingle<(int id, string name)>(SQL, new { Id = (int?)null, Name = "newName" });

-- edit You can access the returned values by -- 编辑您可以通过以下方式访问返回值

int iVal = row.Result.id;
string sVal = row.Result.name; 

The biggest drawback to Dapper's Execute() is that it returns "number of rows impacted" (by updates, deletes, etc)... even if all occurs in a transaction which, after an error occurred, was cancelled via ROLLBACK . Dapper 的 Execute() 的最大缺点是它返回“受影响的行数”(受更新、删除等影响)......即使所有这些都发生在一个事务中,该事务在发生错误后通过ROLLBACK取消 The return-value still holds the impacted-row-number before Rollback, tho the transaction was not committed.返回值在回滚之前仍然保留受影响的行号,但事务未提交。 Yikes!!哎呀!!

DynamicParameters() was more complex, but worked. DynamicParameters() 更复杂,但有效。 But in Moq Tests, I encountered a number of exceptions that I couldn't easily resolve.但是在 Moq 测试中,我遇到了许多无法轻松解决的异常。

My solution (similar to Marc and neggenbe's) followed these steps:我的解决方案(类似于 Marc 和 neggenbe 的)遵循以下步骤:

  1. In the SQL stored-procedure, return an integer-value via,在 SQL 存储过程中,通过以下方式返回整数值,
 SELECT -1 -- 0 for success, -1 for error note--> SQL-Returns (ie. RETURN(1)) are ignored for some reason.
  1. Use Dapper as such,像这样使用Dapper,
 int result = conn.QueryFirst<int>(SProcName, new { id = req.Id, value = req.Value }, commandType: CommandType.StoredProcedure); note--> Other commands work as well with differing return types: QueryFirst: result = key/value where value=[return value] QueryFirst<int>: result = integer QuerySingle: Detailed by Marc and neggenbe's answer.
  1. Check result appropriately, as the above examples.适当检查结果,如上例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM