我如何执行插入并返回与Dapper插入的身份?

如何执行插入到数据库并返回插入的身份与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谢谢,回复。 我试过你的解决scheme,但是,仍然是exception跟踪在下面

 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 

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

 string sql = @" INSERT INTO [MyTable] ([Stuff]) VALUES (@Stuff); SELECT CAST(SCOPE_IDENTITY() as int)"; var id = connection.Query<int>(sql, new { Stuff = mystuff}).Single(); 

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

不知道是否因为我正在对付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(); 

您得到的InvalidCastException是由于SCOPE_IDENTITY是一个十进制(38,0) 。

你可以像下面这样通过强制转换来返回它:

 string sql = @" INSERT INTO [MyTable] ([Stuff]) VALUES (@Stuff); SELECT CAST(SCOPE_IDENTITY() AS INT)"; int id = connection.Query<int>(sql, new { Stuff = mystuff}).Single(); 

如果您正在使用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)); } } 

这是我们最终使用的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表重复列引用。

更多关于它的文档: 链接