How do I perform an insert and return inserted identity with Dapper?

匿名 (未验证) 提交于 2019-12-03 08:59:04

问题:

How do I perform an insert to database and return inserted identity with Dapper?

I've tried something like this:

string sql = "DECLARE @ID int; " +              "INSERT INTO [MyTable] ([Stuff]) VALUES (@Stuff); " +              "SELECT @ID = SCOPE_IDENTITY()";  var id = connection.Query(sql, new { Stuff = mystuff}).First(); 

But it did't work.

@Marc Gravell thanks, for reply. I've tried your solution but, still same exception trace is below

System.InvalidCastException: Specified cast is not valid  at Dapper.SqlMapper.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 

回答1:

It does support input/output parameters (including RETURN value) if you use DynamicParameters, but in this case the simpler option is simply:

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


回答2:

KB:2019779,"You may receive incorrect values when using SCOPE_IDENTITY() and @@IDENTITY", The OUTPUT clause is the safest mechanism:



回答3:

A late answer, but here is an alternative to the SCOPE_IDENTITY() answers that we ended up using: OUTPUT INSERTED

Return only ID of inserted object:

It allows you to get all or some attributes of the inserted row:

string insertUserSql = @"INSERT INTO dbo.[User](Username, Phone, Email)                         OUTPUT INSERTED.[Id]                         VALUES(@Username, @Phone, @Email);";  int newUserId = conn.QuerySingle(insertUserSql,                                 new                                 {                                     Username = "lorem ipsum",                                     Phone = "555-123",                                     Email = "lorem ipsum"                                 }, tran); 

Return inserted object with ID:

If you wanted you could get Phone and Email or even the whole inserted row:

string insertUserSql = @"INSERT INTO dbo.[User](Username, Phone, Email)                         OUTPUT INSERTED.*                         VALUES(@Username, @Phone, @Email);";  User newUser = conn.QuerySingle(insertUserSql,                                 new                                 {                                     Username = "lorem ipsum",                                     Phone = "555-123",                                     Email = "lorem ipsum"                                 }, tran); 

Also, with this you can return data of deleted or updated rows. Just be careful if you are using triggers because:

Columns returned from OUTPUT reflect the data as it is after the INSERT, UPDATE, or DELETE statement has completed but before triggers are executed.

For INSTEAD OF triggers, the returned results are generated as if the INSERT, UPDATE, or DELETE had actually occurred, even if no modifications take place as the result of the trigger operation. If a statement that includes an OUTPUT clause is used inside the body of a trigger, table aliases must be used to reference the trigger inserted and deleted tables to avoid duplicating column references with the INSERTED and DELETED tables associated with OUTPUT.

More on it in the docs: link



回答4:

The InvalidCastException you are getting is due to SCOPE_IDENTITY being a Decimal(38,0).

You can return it as an int by casting it as follows:

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


回答5:

Not sure if it was because I'm working against SQL 2000 or not but I had to do this to get it to work.

string sql = "DECLARE @ID int; " +              "INSERT INTO [MyTable] ([Stuff]) VALUES (@Stuff); " +              "SET @ID = SCOPE_IDENTITY(); " +              "SELECT @ID";  var id = connection.Query(sql, new { Stuff = mystuff}).Single(); 


回答6:

If you're using Dapper.SimpleSave:

 //no safety checks  public static int Create(object param)     {         using (SqlConnection conn = new SqlConnection(GetConnectionString()))         {             conn.Open();             conn.Create((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));         }     } 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!