2013-01-09 41 views
11

我试图调用存储过程using Dapper.Net并获取返回值。使用存储过程从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<int>("INCIDENT_ID"); 

我试了几个不同的东西,参数方向和使用"@INCIDENT_ID"。如果单步执行结果,则可以看到retResults值中正确的返回值降低,但我无法按照以下文档中描述的方式访问值。

存储过程 小巧玲珑的支持完全存储的特效:

var user = cnn.Query<User>("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<int>("@b"); 
int c = p.Get<int>("@c"); 
+0

你是什么意思'我无法按照文档中描述的方式访问这些值' – MethodMan

+1

你有没有尝试 'var IncidentID = con.Query (“usp_GetIncidentID”,commandType:CommandType.StoredProcedure).SingleOrDefault();'?如果你的存储过程通过“select”返回值,这是最简单的,并且可以工作。 – 2013-01-09 21:56:23

+0

刚刚尝试过,我回来了 {DapperRow,INCIDENT_ID ='902306'},但我之前可以看到,但尝试访问该值时遇到问题。 – yellowfever

回答

0

可以读取值,如下

var incidentId = retResults.ToList()[0].INCIDENT_ID; 
+2

当您尝试获得具有空结果集的返回值时,它不起作用! – alerya

5

嫌疑(未经测试),这纯粹是如何命名的参数不匹配;尝试(注意是删除@):

p.Add("INCIDENT_ID", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue); 

var retResults = con.Execute("usp_GetIncidentID", p, commandType:CommandType.StoredProcedure); 

int IncidentID = p.Get<int>("INCIDENT_ID"); 
+0

马克,我玩弄了'@'符号,我在某处看到它有所作为,但事实并非如此。我找回了正确的值,因为我可以查看观察窗口并查看结果中的值。我只是不完全确定如何让他们“正确”的方式。恩。 retResults = {DapperRow,INCIDENT_ID ='902479'} 感谢您的回应! – yellowfever

+0

是数据网格中的结果吗?问题建议你更新参数... –

+0

Marc,是的,这是结果。据我了解的文件,你应该作为参数传递值返回类型为“ParameterDirection.ReturnValue”。结果正确回来,我只是无法使用“p.get (”INCIDENT_ID“)映射到这些结果。这就是我没有得到的部分,为什么我无法从中获得正确的值动态参数 并再次感谢您的回复,非常感谢 – yellowfever

0

我遇到了类似的问题,阅读QueryMultiple的结果。第一次调用Read()返回正确的类型,第二次返回一个DapperRow。我发现使用Read()的打印版本:

var lineExists = query.Read<int?>().FirstOrDefault() == 1; 

解决了我的问题。

+1

如果结果集有0行并且您有返回值,那该怎么办? – alerya

0

为简单起见,我已经削减了这一点。我使用的是输出参数,因为这使我可以完全控制传回的数据类型。我可以在任何其他场景中使用此方法,而不仅仅是插入。

存储过程:

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<long>("Id"); 
0

采用小巧玲珑的测试版,我发现这就像一个魅力:

result = dbConnection.ExecuteScalar<int>(typeof(UCCCCException).Name + "_c", 
         obj, commandType: CommandType.StoredProcedure); 

我写一个通用的,用于将任何类型的对象插入到数据库中。

存储过程是这样的:

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在存储过程中。

它完美,并让我在我的仓库这样的编写一个通用的INSERT命令:

 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<int>(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或任何其他设备,它们要求您为通用存储库中的每个类使用不同的插入或更新方法。

0

DynamicParameters解决方案对我来说并不干净。使存储过程代码返回一个整数(Select 1;)并使用dapper好得多ExecuteScalar<int>("[sp_name]", params);