C# 如何使用Dapper从查询中获取返回值?
我正在尝试使用Dapper从插入查询中获取返回值 以下是我如何让它工作的:C# 如何使用Dapper从查询中获取返回值?,c#,return-value,firebird,dapper,firebird-.net-provider,C#,Return Value,Firebird,Dapper,Firebird .net Provider,我正在尝试使用Dapper从插入查询中获取返回值 以下是我如何让它工作的: // 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\") " + "VA
// 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");
}
我在简洁的代码中犯了什么错误?为什么一个版本可以而另一个版本不行?我已经读到Dapper执行ExecuteOnQuery,所以我不认为这是原因。returning子句的行为类似于select,因为它在结果网格中返回数据。因此,您的查询应该作为查询执行。这还具有显著简化调用代码的优点:
var newId=conn.QuerySingleSQL,new{Id=int?null,Name=newName};
如果需要其他字段,可以将其扩展为使用与返回的列匹配的自定义返回类型或值元组。例如:
var row=conn.QuerySingleSQL,new{Id=int?null,Name=newName};
或
var row=conn.QuerySingleSQL,new{Id=int?null,Name=newName};
-编辑
您可以通过以下方式访问返回的值:
int iVal=row.Result.id;
字符串sVal=row.Result.name;
returning子句的作用类似于select,因为它返回结果网格中的数据。因此,您的查询应该作为查询执行。这还具有显著简化调用代码的优点:
var newId=conn.QuerySingleSQL,new{Id=int?null,Name=newName};
如果需要其他字段,可以将其扩展为使用与返回的列匹配的自定义返回类型或值元组。例如:
var row=conn.QuerySingleSQL,new{Id=int?null,Name=newName};
或
var row=conn.QuerySingleSQL,new{Id=int?null,Name=newName};
-编辑
您可以通过以下方式访问返回的值:
int iVal=row.Result.id;
字符串sVal=row.Result.name;
Dapper的Execute最大的缺点是它返回受更新、删除等影响的行数。。。即使所有事务都发生在错误发生后通过回滚取消的事务中。返回值在回滚之前仍然保留受影响的行号,尽管事务未提交。哎呀 动态参数更复杂,但有效。但在Moq测试中,我遇到了一些我无法轻松解决的异常 我的解决方案与Marc和neggenbe的类似,遵循以下步骤: 在SQL存储过程中,通过返回一个整数值, 用整洁的方式, 如上述示例所示,适当检查结果。
Dapper的Execute最大的缺点是它返回受更新、删除等影响的行数。。。即使所有事务都发生在错误发生后通过回滚取消的事务中。返回值在回滚之前仍然保留受影响的行号,尽管事务未提交。哎呀 动态参数更复杂,但有效。但在Moq测试中,我遇到了一些我无法轻松解决的异常 我的解决方案与Marc和neggenbe的类似,遵循以下步骤: 在SQL存储过程中,通过返回一个整数值, 用整洁的方式, 如上述示例所示,适当检查结果。
您必须从数据库中读取以获取更新的值。您需要执行Select查询。@jdweng不一定;direct ado.net代码使用ExecuteOnQuery,因此这应该可以类似地工作。但是,我同意@jdweng的观点,即在返回时阅读文档,这可能应该是一种查询用法。坦白地说,我不清楚为什么cmd.ExecuteNonQuery版本可以工作。事实上,我使用它来获取几个值返回新ID和一些同步内容的时间戳-目标不是插入/更新数据,然后进行第二次查询以获取更新的数据,就我所知,这正是返回应该用于的…@neggenbe yes,但问题是它是如何回来的;如果它作为一个结果网格返回,那么它应该使用Query执行——尽管命令完全相同——而不是两个查询;您必须从数据库中读取以获取更新的值。您需要执行Select查询。@jdweng不一定;direct ado.net代码使用ExecuteOnQuery,因此这应该可以类似地工作。但是,我同意@jdweng的观点,即在返回时阅读文档,这可能应该是一种查询用法。坦白地说,我不清楚为什么cmd.ExecuteNonQuery版本可以工作。事实上,我使用它来获取几个值返回新ID和一些同步内容的时间戳-目标不是插入/更新数据,然后进行第二次查询以获取更新的数据,就我所知,这正是返回应该用于的…@neggenbe yes,但问题是它是如何回来的;如果它作为一个结果网格返回,那么它应该使用Query执行——尽管命令完全相同——而不是两个查询;旁注:我还没有设法让FbConnection在本地连接以全面查看差异,但我已经让ISQL工具来验证returning子句的行为。我将尝试一下,并让您知道它是否也在工作。Thx为th
不管怎样,我都会收到宝贵的反馈!ok更新了您的答案,以确保它还包含实际读取返回结果的代码。成功了,万分感谢!在Firebird内部,带有RETURNING子句的语句不像select语句那样工作。它是一个单例结果行,在执行之后立即返回,因此不需要从中获取游标。这可能也解释了为什么ExecuteOnQuery可以直接使用Firebird.net提供程序。从技术上讲,它是一个不带列的可执行存储过程。@neggenbe不是当前的;您可以使用Select或SelectMany来填充它,不过:var results=source.Selectx=>conn.QuerySinglesql,new{…x…}.ToList;如果使用Query而不是QuerySingleSide,请选择many注意:我还没有设法让FbConnection在本地连接以完全查看差异,但我已经使用ISQL工具来验证returning子句的行为。我将尝试一下,并让您知道它是否工作正常。谢谢你宝贵的反馈!ok更新了您的答案,以确保它还包含实际读取返回结果的代码。成功了,万分感谢!在Firebird内部,带有RETURNING子句的语句不像select语句那样工作。它是一个单例结果行,在执行之后立即返回,因此不需要从中获取游标。这可能也解释了为什么ExecuteOnQuery可以直接使用Firebird.net提供程序。从技术上讲,它是一个不带列的可执行存储过程。@neggenbe不是当前的;您可以使用Select或SelectMany来填充它,不过:var results=source.Selectx=>conn.QuerySinglesql,new{…x…}.ToList;如果使用Query而不是QuerySingle,请选择many
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();
}
SELECT -1 -- 0 for success, -1 for error
note--> SQL-Returns (ie. RETURN(1)) are ignored for some reason.
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.