FlexLabs.Upsert icon indicating copy to clipboard operation
FlexLabs.Upsert copied to clipboard

Return Id of newly upserted row

Open akraines opened this issue 6 years ago • 11 comments

How can I retrieve the Id of the upserted row? Something like this: https://stackoverflow.com/a/31578591/5683904

akraines avatar Oct 27 '18 21:10 akraines

Hi @akraines,

That's definitely a good feature to have. I've been having some thoughts on this, and I'm planning to add this in a future release, most likely in v2.1

artiomchi avatar Nov 03 '18 14:11 artiomchi

Actually it would be good if the whole thing can be returned (i.e. in Npgsql you can have Returning *)

schmitch avatar Nov 28 '18 18:11 schmitch

Is this feature still planned?

PeteOnTheGitHub avatar Jun 07 '19 03:06 PeteOnTheGitHub

I might be able to help with this as I am looking for the same solution. I was checking the code to see what it takes to implement and this is what I came up with:

  1. In the UpsertCommandBuilder, create a new method WithResults that define the format the results need to be returned on:
public UpsertCommandBuilder<TEntity> WithResults(Expression<Func<TEntity, TEntity, TEntity>> resultDefinition)
        {
            if (_resultExpression != null)
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, Resources.CantCallMethodTwice, nameof(WithResults)));

            _resultExpression = resultDefinition ?? throw new ArgumentNullException(nameof(resultDefinition));
            return this;
        }
  1. Change the int Run and Task RunAsync methods is probably not a good idea so I would create 2 new methods:
// note that they return a collection of TEntity to account for multiple records affected
IEnumerable<TEntity> RunWithResults();
Task<IEnumerable<TEntity>> RunWithResultsAsync(CancellationToken token = default)
  1. New overload methods should be created in the IUpsertCommandRunner implementations. This is similar to UpsertCommandBuilder.

  2. Update the PrepareCommand and GenerateCommand methods for each implementation to build the output clause. I can easily do the SQL Server version, but might need help with the others.

@artiomchi this is an extra simplistic description of the changes, but I don't want to start anything without knowing the direction is right.

Cheers, Lucas

jlucaspains avatar Oct 15 '20 00:10 jlucaspains

What is the status of this request/issue? Seems like the requirement is to return the ID of the new or existing record is important to the upsert pattern. Is there a correct way to do this? I don't see my model entities receive the IDs after running dbcontext.upsert().

kzeitz avatar Dec 16 '21 04:12 kzeitz

This library would be perfect if it has this feature (return the existing / new row). Unfortunately without it it's not usable :(

crazyfx1 avatar Jun 08 '22 08:06 crazyfx1

@crazyfx1 Could not agree more. Without returning the existing/new row this is not usable.

radenkozec avatar Nov 15 '22 14:11 radenkozec

I was lucky enough to be upserting with a client-generated guid, so a simple select gets me the new row back. Not ideal, but definitely working.

owns avatar Nov 19 '22 15:11 owns

@artiomchi Hi! Is it still planned?

AntonSmolkov avatar Jan 19 '23 10:01 AntonSmolkov

+1

kbzowski avatar Feb 22 '23 10:02 kbzowski

I might be able to help with this as I am looking for the same solution. I was checking the code to see what it takes to implement and this is what I came up with:

  1. In the UpsertCommandBuilder, create a new method WithResults that define the format the results need to be returned on:
public UpsertCommandBuilder<TEntity> WithResults(Expression<Func<TEntity, TEntity, TEntity>> resultDefinition)
        {
            if (_resultExpression != null)
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, Resources.CantCallMethodTwice, nameof(WithResults)));

            _resultExpression = resultDefinition ?? throw new ArgumentNullException(nameof(resultDefinition));
            return this;
        }
  1. Change the int Run and Task RunAsync methods is probably not a good idea so I would create 2 new methods:
// note that they return a collection of TEntity to account for multiple records affected
IEnumerable<TEntity> RunWithResults();
Task<IEnumerable<TEntity>> RunWithResultsAsync(CancellationToken token = default)
  1. New overload methods should be created in the IUpsertCommandRunner implementations. This is similar to UpsertCommandBuilder.
  2. Update the PrepareCommand and GenerateCommand methods for each implementation to build the output clause. I can easily do the SQL Server version, but might need help with the others.

@artiomchi this is an extra simplistic description of the changes, but I don't want to start anything without knowing the direction is right.

Cheers, Lucas

I think along with you might need to update GetCommandRunner to include a select statement at the end of the merge statement to return both the inserted or updated rows after the merge is complete for these two new methods. Or allow to pass the runners as a config value. So that we can create our own instance of IUpsertCommandRunner. This might not be as simple of as adding two new methods. Needs some more to it.

vamsidogiparthi avatar Mar 06 '23 17:03 vamsidogiparthi