Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DbUpdateException should not leave the context in a bad state #29060

Open
yonidagan opened this issue Sep 12, 2022 · 4 comments
Open

DbUpdateException should not leave the context in a bad state #29060

yonidagan opened this issue Sep 12, 2022 · 4 comments

Comments

@yonidagan
Copy link

EF is wrongly adding (persisting) an entity when a duplicate key is found.

Consider the following Entity, when Name is set as Alternate Key:

  public class MyEntity
    {
        [Key]
        public int Id { get; set; }
        
        // name is AlternateKey, set by modelBuilder
        public string Name { get; set; }
        public string SomeValue { get; set; }
    }

Then consider the following scenario:

  1. Add Entity1 with name "Foo".
  2. SaveChanges -> Db is updated correctly and table now contains Entity1
  3. Add Entity2 with name "Foo" -> exception is thrown (duplicate key) (see exception below)
  4. Delete Entity1.
    1. Save Changes -> DB is updated so that Entity1 is deleted but Entity2 is saved!
      One would not expect Entity1 to be saved after an error occured when adding it to the Dbset.
      Yet, it looks like it is left in DbSet.Local and, with an Added State and is Added to the Db once Entity1 is removed.

Exception on step 3 is:

Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
---> Microsoft.Data.SqlClient.SqlException (0x80131904): Violation of UNIQUE KEY constraint 'AK_MyEntities_Name'. Cannot insert duplicate key in object 'dbo.MyEntities'. The duplicate key value is (Foo).
The statement has been terminated.

The following code simulates that process:

try
{
    MyDbContext db = new MyDbContext();

    MyEntity e1 = new MyEntity() { Name = "Foo", SomeValue = "Value1" };
    db.MyEntities.Add(e1);
    db.SaveChanges();

    MyEntity e2 = new MyEntity() { Name = "Foo", SomeValue = "Value2" };
    try
      {
        db.MyEntities.Add(e2);
      }
      catch (Exception ex)
      // Exception is thrown here
      {
        Console.WriteLine(ex);
       }
  db.MyEntities.Remove(e1);
  db.SaveChanges();
  // e1 is deleted but e2 is persisted in the Db!
}
catch (Exception ex)
{
  Console.WriteLine(ex);
}

It seems the DbSet.Local is wrongly updated with the entity even though an exception was thrown during the call to .Add
A full console app sample project to reproduce this issue is attached.


EF Core version: 6.0.8
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 6.0
EFDuplicateKey.zip

@ajcvickers
Copy link
Member

Note for triage: The context should be considered in an invalid state after an InvalidOperationException has been thrown--dotnet/EntityFramework.Docs#3401 tracks documenting this better. We should discuss if this also applies to DbUpdateException. (Note that it does not apply to DbUpdateConcurrencyException.)

@ajcvickers
Copy link
Member

Note from triage: DbUpdateException should not leave the context in a bad state.

@sagilevanon

This comment was marked as resolved.

@ajcvickers

This comment was marked as resolved.

@ajcvickers ajcvickers removed their assignment Aug 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants