Comment effectuer un insert et retourner l'identité insérée avec Dapper?

comment effectuer un insert dans la base de données et retourner l'identité insérée avec Dapper?

j'ai essayé quelque chose comme ça:

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

mais ça n'a pas marché.

@Marc Gravell merci, pour la réponse. J'ai essayé votre solution mais, toujours la même exception trace est en dessous de

System.InvalidCastException: Specified cast is not valid

at Dapper.SqlMapper.<QueryInternal>d__a`1.MoveNext() in (snip)DapperSqlMapper.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)DapperSqlMapper.cs:line 538
at Dapper.SqlMapper.Query[T](IDbConnection cnn, String sql, Object param) in (snip)DapperSqlMapper.cs:line 456
135
demandé sur Charles Burns 2011-11-25 18:02:15

6 réponses

Il ne support entrée/sortie paramètres (y compris les RETURN ) si vous utilisez DynamicParameters , mais dans ce cas, l'option plus simple est tout simplement:

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

var id = connection.Query<int>(sql, new { Stuff = mystuff}).Single();
235
répondu Marc Gravell 2012-07-10 14:38:44

KB: 2019779 , " vous pouvez recevoir des valeurs incorrectes en utilisant SCOPE_IDENTITY () et @IDENTITY@", La clause de sortie est le mécanisme le plus sûr:

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();
43
répondu jww 2012-09-28 05:39:23

une réponse tardive, mais voici une alternative à la SCOPE_IDENTITY() réponses que nous avons fini par utiliser: sortie insérée

retour seulement ID de l'objet inséré:

il vous permet d'obtenir tous ou certains attributs de la ligne insérée:

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

retour objet inséré avec ID:

si vous vous pouvez obtenir Phone et Email ou même la ligne entière insérée:

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

aussi, avec cela vous pouvez retourner les données de supprimé ou mis à jour lignes. Faites juste attention si vous utilisez des déclencheurs parce que:

les colonnes retournées de la sortie reflètent les données telles qu'elles sont après la Insérer, mettre à jour, ou supprimer la déclaration a terminé, mais avant déclencher sont exécutées.

pour au lieu de déclencheurs, les résultats retournés sont générés comme si le INSERT, UPDATE, ou DELETE avait réellement eu lieu, même si aucune les modifications ont lieu à la suite de l'opération de déclenchement. Si un l'énoncé qui inclut une clause de sortie est utilisé à l'intérieur du corps d'un trigger, les alias de table doivent être utilisés pour référencer le trigger inséré et des tableaux supprimés pour éviter de dupliquer les références de colonne avec le INSERTED et DELETED tableaux associés à la production.

plus sur elle dans les documents: lien

19
répondu Tadija Bagarić 2018-01-17 20:05:54

L'InvalidCastException que vous obtenez est due à SCOPE_IDENTITY étant un décimal(38,0) .

vous pouvez le retourner comme un int en le moulant comme suit:

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

int id = connection.Query<int>(sql, new { Stuff = mystuff}).Single();
5
répondu bpruitt-goddard 2017-05-23 12:10:41

Je ne suis pas sûr que ce soit parce que je travaille contre SQL 2000 ou pas, mais je devais le faire pour que ça marche.

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();
4
répondu mytydev 2012-04-18 21:01:07

si vous utilisez 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
répondu Lodlaiden 2016-08-22 11:22:32