如何使用Dapper执行插入并返回插入的标识?

问题描述 投票:153回答:7

如何对数据库执行插入并使用Dapper返回插入的标识?

我尝试过这样的事情:

string sql = "DECLARE @ID int; " +
             "INSERT INTO [MyTable] ([Stuff]) VALUES (@Stuff); " +
             "SELECT @ID = SCOPE_IDENTITY()";

var id = connection.Query<int>(sql, new { Stuff = mystuff}).First();

但它没有用。

@Marc Gravell谢谢你的回复。我已经尝试过你的解决方案但是,下面仍有相同的异常跟踪

System.InvalidCastException: Specified cast is not valid

at Dapper.SqlMapper.<QueryInternal>d__a`1.MoveNext() in (snip)\Dapper\SqlMapper.cs:line 610
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at Dapper.SqlMapper.Query[T](IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Boolean buffered, Nullable`1 commandTimeout, Nullable`1 commandType) in (snip)\Dapper\SqlMapper.cs:line 538
at Dapper.SqlMapper.Query[T](IDbConnection cnn, String sql, Object param) in (snip)\Dapper\SqlMapper.cs:line 456
c# sql-server dapper
7个回答
261
投票

如果你使用RETURN,它确实支持输入/输出参数(包括DynamicParameters值),但在这种情况下,更简单的选项就是:

string sql = @"
INSERT INTO [MyTable] ([Stuff]) VALUES (@Stuff);
SELECT CAST(SCOPE_IDENTITY() as int)";

var id = connection.Query<int>(sql, new { Stuff = mystuff}).Single();

47
投票

KB:2019779,“使用SCOPE_IDENTITY()和@@ IDENTITY时可能会收到不正确的值”,OUTPUT子句是最安全的机制:

string sql = @"
DECLARE @InsertedRows AS TABLE (Id int);
INSERT INTO [MyTable] ([Stuff]) OUTPUT Inserted.Id INTO @InsertedRows
VALUES (@Stuff);
SELECT Id FROM @InsertedRows";

var id = connection.Query<int>(sql, new { Stuff = mystuff}).Single();

32
投票

一个迟到的答案,但这里是我们最终使用的SCOPE_IDENTITY()答案的替代品:OUTPUT INSERTED

仅返回插入对象的ID:

它允许您获取插入行的全部或部分属性:

string insertUserSql = @"INSERT INTO dbo.[User](Username, Phone, Email)
                        OUTPUT INSERTED.[Id]
                        VALUES(@Username, @Phone, @Email);";

int newUserId = conn.QuerySingle<int>(insertUserSql,
                                new
                                {
                                    Username = "lorem ipsum",
                                    Phone = "555-123",
                                    Email = "lorem ipsum"
                                }, tran);

返回带ID的插入对象:

如果你想要你可以得到PhoneEmail甚至整个插入的行:

string insertUserSql = @"INSERT INTO dbo.[User](Username, Phone, Email)
                        OUTPUT INSERTED.*
                        VALUES(@Username, @Phone, @Email);";

User newUser = conn.QuerySingle<User>(insertUserSql,
                                new
                                {
                                    Username = "lorem ipsum",
                                    Phone = "555-123",
                                    Email = "lorem ipsum"
                                }, tran);

此外,使用此功能,您可以返回已删除或更新的行的数据。如果您使用触发器,请小心,因为:

从OUTPUT返回的列反映了在INSERT,UPDATE或DELETE语句完成之后但在执行触发器之前的数据。

对于INSTEAD OF触发器,生成的返回结果就像INSERT,UPDATE或DELETE实际发生一样,即使触发操作没有发生任何修改也是如此。如果在触发器主体内部使用包含OUTPUT子句的语句,则必须使用表别名来引用触发器插入和删除的表,以避免使用与OUTPUT关联的INSERTED和DELETED表重复列引用。

更多关于它的文档:link


5
投票

您获得的InvalidCastException是由于SCOPE_IDENTITY是Decimal(38,0)

您可以通过如下方式将其作为int返回:

string sql = @"
INSERT INTO [MyTable] ([Stuff]) VALUES (@Stuff);
SELECT CAST(SCOPE_IDENTITY() AS INT)";

int id = connection.Query<int>(sql, new { Stuff = mystuff}).Single();

4
投票

不确定是不是因为我正在使用SQL 2000,但我不得不这样做才能让它工作。

string sql = "DECLARE @ID int; " +
             "INSERT INTO [MyTable] ([Stuff]) VALUES (@Stuff); " +
             "SET @ID = SCOPE_IDENTITY(); " +
             "SELECT @ID";

var id = connection.Query<int>(sql, new { Stuff = mystuff}).Single();

0
投票

如果你正在使用Dapper.SimpleSave:

 //no safety checks
 public static int Create<T>(object param)
    {
        using (SqlConnection conn = new SqlConnection(GetConnectionString()))
        {
            conn.Open();
            conn.Create<T>((T)param);
            return (int) (((T)param).GetType().GetProperties().Where(
                    x => x.CustomAttributes.Where(
                        y=>y.AttributeType.GetType() == typeof(Dapper.SimpleSave.PrimaryKeyAttribute).GetType()).Count()==1).First().GetValue(param));
        }
    }

0
投票

有一个很棒的库让你的生活更轻松Dapper.Contrib.Extensions。包括这个之后你可以写:

public int Add(Transaction transaction)
{
        using (IDbConnection db = Connection)
        {
                return (int)db.Insert(transaction);
        }
}
© www.soinside.com 2019 - 2024. All rights reserved.