2011-11-04 124 views
3

我目前正在使用的系统使用所有数据访问的存储过程。我目前正在研究Dapper(迄今为止它看起来很棒),但我想知道是否可以使用使用Template创建的DynamicParameters对象,但将其中一个参数设置为输出参数。例如:我可以在Template中使用DynamicParameters并在dapper中使用返回参数吗?

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

代码:

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

目前我收到一个错误,因为键没有被发现。有没有办法获得ID输出参数,而无需手动设置所有存储的procs参数?

回答

4

一个快速的调整,现在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实例中获取(如图所示)。

+0

+1为解释和项目更新这导致 –

+0

看起来不错,离开我的笔记本电脑在办公室周末,但我会检查星期一。谢谢! – Fermin

+0

@Fermin做到了吗? –

2

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

我认为不理想的另一个想法是修改Dapper代码并将Remove方法添加到DynamicParameters类中以删除不需要的参数。这并不能节省你很多,但是你仍然会花时间指定为了使存储过程快乐而删除所有参数。如果您决定实施此操作,请记住在指定要从parameters字典中删除的密钥时该情况很重要。

+0

我试过这个,但我得到一个异常“过程或函数InsertPerson有太多的参数指定。”。对不起,应该在问题中提出这个问题。 – Fermin

+0

@Fermin当参数包含的参数比存储过程中声明的参数个数更多时,会出现异常。由于您将'person'作为模板传递给'DynamicParameters'构造函数,因此'Person'类的所有属性都有一个为其生成的参数。所以我怀疑你的班上有更多的属性,而不仅仅是'ID','Name'和'DOB'。如果是这种情况,那么我认为你需要自己指定参数,通过添加它们,如上所示。 –

+0

我很怀疑,我正在尝试编写一个通用的DataAccess类,并试图避免单独指定参数。 – Fermin

相关问题