Search code examples
dapper

Is it possible to run an Insert and Get by dapper simultaneously?


Using ASP.NET Core3.1 and Dapper, I want to insert a record to my database and get the whole table as result ! Currently I have two queries in my repository as below: First: to insert a record to my data base:

   //some codes here
  string sql = "UPDATE likes AS L SET L.isLike = @isLikeSQL WHERE L.ItemId = @ItemIdSQL  AND L.Ip = @IpSQL ";
  await dbConnection.ExecuteAsync(sql, new { ItemIdSQL = ItemId, senderpSQL = Ip, isLikeSQL = isLike });

Second: To get the whole table after inserting the top record:

//some codes here
string sql = " SELECT COUNT(*) FROM likes AS I WHERE I.ItemId = @itemIdSQL  AND I.isLike=1; " +
            " SELECT COUNT(*) FROM map118.likes AS I WHERE I.ItemId = @itemIdSQL  AND I.isLike=0; ";
using (var data = await dbConnection.QueryMultipleAsync(sql, new { itemIdSQL = ItemId }))
    {
      numberOfLikes = data.Read<int>().FirstOrDefault();
      numberOfDislikes = data.Read<int>().FirstOrDefault();
    }

I need to know if I can have all above in one query by dapper !! In fact we have QueryMultipleAsync in dapper that can manage more than one query ( AS I have done myself ) but I do not know if we can merge an ExecuteAsync and QueryAsync and have them all in one query for better performance. I need something like this :

string sql =
 "UPDATE likes AS L SET L.isLike = @isLikeSQL WHERE L.ItemId = @ItemIdSQL  AND  L.Ip = @IpSQL " +
 " SELECT COUNT(*) FROM likes AS I WHERE I.ItemId = @itemIdSQL  AND  L.isLike=1; "

using (var data = await dbConnection.QueryOrExecute???(sql, new { itemIdSQL = ItemId }))
    {
      numberOfLikes = data.Read<int>().FirstOrDefault();
      numberOfDislikes = data.Read<int>().FirstOrDefault();
    }

Solution

  • UPDATE doesn't return a grid (unless you are using the OUTPUT clause. You can do as many operations as you like in a SQL operation - all that Dapper cares about is the result grids, so yes, you can perform an update and (separately) a select. The only significance of Execute over Query is that Execute expects zero grids. If you're returning a single grid, then Query; if you're returning multiple grids: QueryMultiple. Dapper has no interest in what happens inside the query - it is entirely opaque - all it sees is result grids.

    I highly recommend using the formal operation separator (;), though. For example:

    const string sql = @"
    UPDATE likes AS L
    SET L.isLike = @isLike
    WHERE L.ItemId = @ItemId AND L.Ip = @Ip;
    
    SELECT COUNT(*) FROM likes AS I WHERE I.ItemId = @ItemId AND L.isLike=1;
    SELECT COUNT(*) FROM likes AS I WHERE I.ItemId = @ItemId AND L.isLike=0;
    "
    using (var data = await dbConnection.QueryMultipleAsync(sql,
        new { ItemId, isLike, Ip }))
    {
        numberOfLikes = data.ReadSingle<int>();
        numberOfDislikes = data.ReadSingle<int>();
    }
    

    although to be honest I might be tempted to do, instead, a single final select, using Dapper's positional treatment of value-tuples:

    const string sql = @"
    UPDATE likes AS L
    SET L.isLike = @isLike
    WHERE L.ItemId = @ItemId AND L.Ip = @Ip;
    
    SELECT 
        (SELECT COUNT(*) FROM likes AS I WHERE I.ItemId = @ItemId AND L.isLike=1),
        (SELECT COUNT(*) FROM likes AS I WHERE I.ItemId = @ItemId AND L.isLike=0);
    "
    (var numberOfLikes, var numberOfDislikes) =
        await dbConnection.QuerySingleAsync<(int,int)>(sql,
        new { ItemId, isLike, Ip });
    

    or something involving group by L.isLike