Dapper.Contrib icon indicating copy to clipboard operation
Dapper.Contrib copied to clipboard

Dapper.Contrib [ExplicitKey] attribute behaves like the [Key] attribute when using with IDbConnection.InsertAsync()

Open DamienLaw opened this issue 7 years ago • 6 comments

I have a model

public class TestModel
{
    [ExplicitKey]
    public int ExplicitId1 { get; set; }

    [ExplicitKey]
    public int ExplicitId2 { get; set; }

    public int Property1 { get; set; }
}

When I performed a IDbConnection.InsertAsync(), everything is working as expected

var model = new TestModel
{
    ExplicitId1 = 1,
    ExplicitId2 = 2,
    Property1 = 3
};

await dbConnection.InsertAsync(model);
// The SQL Statement that is being generated:
// INSERT INTO Test (ExplicitId1, ExplicitId2, Property1) VALUES (@ExplicitId1, @ExplicitId2, @Property1)

Now, things start to go wrong when I performed an IDbConnection.UpdateAsync() first followed by an IDbConnection.InsertAsync().

if (!await dbConnection.UpdateAsync(model))
{
    await dbConnection.InsertAsync(model);
    // The SQL Statement that is being generated:
    // INSERT INTO Test (Property1) VALUES (@Property1)
}

The INSERT SQL Statement that is being generated has excluded the Properties decorated with the ExplicitKey attribute. The columns ExplicitId1 and ExplicitId2 are composite key in the database table which aren't auto generated but have to be supplied. An error will be thrown if the above INSERT statement is executed since the columns aren't provided.

I think I have located the source of the problem in the source file SqlMapperExtensions.Async.cs The line keyProperties.AddRange(explicitKeyProperties); adds "Explicit Key Properties" into the list of "Key Properties" effectively treating ExplicitKeys as Keys and caching them for subsequent uses. Property decorated with the Key attribute is treated as an auto-generated column in the database table and hence excluded from the INSERT statement generated.

DamienLaw avatar Jul 18 '18 17:07 DamienLaw

Oh wait, this has been fixed a month ago but only for UpdateAsync().

Shouldn't DeleteAsync() be fixed as well since that part is used on both methods?

DamienLaw avatar Jul 19 '18 02:07 DamienLaw

When will this change/pre-release related to this change be released to NuGet?

panmona avatar Sep 24 '18 09:09 panmona

DeleteAsync() still hasn't been fixed as of 1.60.1

achaloux avatar Mar 14 '19 20:03 achaloux

DeleteAsync() is still an issue with the latest nuget version of Dapper.Contrib. Any ideas @NickCraver or @mgravell? We ran into this issue and it took quite a while to realize what it was so now we reverted to using Dapper instead with ExecuteAsync().

psjflynn avatar Jun 04 '19 13:06 psjflynn

This issue should be closed. It was fixed in pull request DapperLib/Dapper#1309 and released in version 2.0.30

achaloux avatar Oct 10 '19 21:10 achaloux