使用存储过程从Dapper.net查询返回值
我试图using Dapper.Net
调用存储过程并获取返回值。
p.Add("@INCIDENT_ID", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue); var retResults = con.Execute("usp_GetIncidentID", p, commandType:CommandType.StoredProcedure); int IncidentID = p.Get("INCIDENT_ID");
我已经尝试了几个不同的参数方向并使用"@INCIDENT_ID"
。 如果单步retResults
结果,可以看到正确的返回值在retResults
值中下降,但我无法按照下面的文档中描述的方式访问这些值。
存储过程Dapper支持完全存储的过程:
var user = cnn.Query("spGetUser", new {Id = 1}, commandType: CommandType.StoredProcedure).First();}}} If you want something more fancy, you can do: var p = new DynamicParameters(); p.Add("@a", 11); p.Add("@b", dbType: DbType.Int32, direction: ParameterDirection.Output); p.Add("@c", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue); cnn.Execute("spMagicProc", p, commandType: commandType.StoredProcedure); int b = p.Get("@b"); int c = p.Get("@c");
您可以阅读以下值
var incidentId = retResults.ToList()[0].INCIDENT_ID;
我怀疑 (未经测试)这与你如何命名参数完全不匹配; 尝试(注意删除的@
):
p.Add("INCIDENT_ID", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue); var retResults = con.Execute("usp_GetIncidentID", p, commandType:CommandType.StoredProcedure); int IncidentID = p.Get("INCIDENT_ID");
我在读取QueryMultiple的结果时遇到了类似的问题。 第一次调用Read()返回正确的类型,第二次调用返回DapperRow。 我发现使用类型化的Read():
var lineExists = query.Read().FirstOrDefault() == 1;
解决了我的问题。
我为了简单而减少了这一点。 我正在使用输出参数,因为这使我可以完全控制传回的数据类型。 我可以将此方法用于任何其他场景,而不仅仅是插入。
存储过程:
ALTER PROCEDURE User_Insert ( @EmailAddress nvarchar(255), @Id bigint OUT ) AS INSERT INTO User ( [EmailAddress] ) VALUES ( @EmailAddress ) set @Id = SCOPE_IDENTITY()
存储库代码:
var sql = "Execute User_Insert @EmailAddress, @Id = @Id OUTPUT"; var _params = new DynamicParameters(); _params.Add("EmailAddress", user.EmailAddress); _params.Add("Id", dbType: DbType.Int64, direction: ParameterDirection.Output); using (var connection = new SqlConnection(ConnectionString)) { connection.Open(); using (var transaction = connection.BeginTransaction()) { var result = SqlMapper.Execute(connection, sql, param, transaction); transaction.Commit(); } } var id = _params.Get("Id");
使用Dapper的测试版本,我发现这就像一个魅力:
result = dbConnection.ExecuteScalar(typeof(UCCCCException).Name + "_c", obj, commandType: CommandType.StoredProcedure);
我正在编写一个generics,用于将任何类型的对象插入数据库。
存储过程如下所示:
ALTER PROCEDURE [dbo].[UCCCCException_c] ( @Id int = null, @ExceptionDate datetime = null, @HResult int = 0, @Message varchar(8000) = null, @Source varchar(8000) = null, @StackTrace varchar(8000) = null, @Module varchar(8000) = null, @Name varchar(8000) = null, @created_at datetime = null, @updated_at datetime = null, @created_by int = null, @updated_by int = null , @Creator varchar(255) = null, @Updator varchar(255) = null ) AS -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON; Insert into dbo.uccccexceptions ( ExceptionDate, HResult, [Message], [Source], StackTrace, Module, Name) values ( coalesce(@ExceptionDate,getdate()), @HResult, @Message, @Source, @StackTrace, @Module, @Name ) ; select @@Identity; go
需要注意的是,您必须为正在使用的类中的每个属性指定一个条目,即使目标表中不存在这些属性,也必须为存储过程的参数。 如果您有许多字段是MVC情况下的视图字段,这可能会很烦人。
要获取返回值,您只需使用Execute,并确保您的最后一个语句是存储过程中的Select @@ Identity。
它工作得很好,并允许我在我的存储库中编写一个通用插入命令,如下所示:
public virtual int Insert(T obj) { int result = -2; if (!databaseOnline) { throw new Exception(HttpStatusCode.ServiceUnavailable.ToString()); } if (obj != null) { try { using (IDbConnection dbConnection = ConnectionProvider.OpenConnection()) { dbConnection.Open(); result = dbConnection.ExecuteScalar(typeof(T).Name + "_c", obj, commandType: CommandType.StoredProcedure); } } catch (SqlException sqlex) { Logger.LogError(sqlex, false); throw; } catch (Exception ex) { Logger.LogError(ex); throw; } } return result; }
我使用我的数据库中的约定,存储过程的名称是类型名称,后跟“_s”表示选择,“_ c”表示插入,“_ d”表示删除,“_ u”表示更新。
PS:我讨厌使用Dapper的DynamicParameters或任何其他要求您为通用存储库中的每个类使用不同插入或更新方法的设备。
DynamicParameters解决方案对我来说并不干净。 最好使存储过程代码返回一个整数(Select 1;)并使用dapper ExecuteScalar