Why does Entity Framework try to insert existing entity?
Asked Answered
D

1

5

I am using Entity Framework (with a code-first approach) and the database is created successfully with the expected foreign keys and unique key constraints.

I have those two model classes:

public class Foo 
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    public Bar Bar { get; set; } 
}

public class Bar
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    [Index(IsUnique = true), StringLength(512)]
    public string Url { get; set; }
}

And this application code:

var foo = GetData();

using (DatabaseContext db = new DatabaseContext())
{
    db.Entry(foo).State = EntityState.Added;

    if (foo.Bar != null)
    {
        var bar = await db.Bar.FirstOrDefaultAsync(x => x.Url == foo.Bar.Url);

        if (bar != null)
        {
            // When I assign an existing entity ...
            foo.Bar = bar;
        }
    }

    // ... following exception will be thrown.
    await db.SaveChangesAsync();
}

SqlException: Cannot insert duplicate key row in object 'dbo.Bar' with unique index 'IX_Url'. The duplicate key value is (https://api.example.com/rest/v1.0/bar/FD6FAB72-DCE2-47DB-885A-424F3D4A70B6). The statement has been terminated.

I don't understand why Entity Framework is trying to add the navigation property Bar, even after obtaining and assigning it from the same DbContext. Similar StackOverflow questions haven't provided any working solution yet.

Please tell me if I need to provide additional information.

Did I forget to set any EF related configuration or something like that? Thank you in advance!

Domel answered 31/3, 2018 at 13:16 Comment(0)
A
8

It's because

db.Entry(foo).State = EntityState.Added;

marks the foo.Bar (and any referenced entity not tracked by the context) as Added as well.

You should resolve the referenced entities before adding the Foo entity:

var foo = GetData();
using (DatabaseContext db = new DatabaseContext())
{
    // Resolve references
    if (foo.Bar != null)
    {
        var bar = await db.Bar.FirstOrDefaultAsync(x => x.Url == foo.Bar.Url);
        if (bar != null)
            foo.Bar = bar;
    }
    // Then add the entity
    db.Entry(foo).State = EntityState.Added;

    await db.SaveChangesAsync();
}
Ambiversion answered 31/3, 2018 at 13:24 Comment(1)
This resolved my problem. Thank you very much dear friend! =)Module

© 2022 - 2024 — McMap. All rights reserved.