Cannot insert duplicate key in object 'dbo.Account'. The duplicate key value is (2)

c# entity-framework entity-framework-6 sql-server

Question

I have the following structure and am using Entity Framework 6.2:

    public class MainModel
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public long Id { get; set; }
        public ModelB ModelB { get; set; }
        public ModelC ModelC { get; set; }
    }

    public class ModelB
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public long Id { get; set; }
        public Account Account { get; set; }
    }

    public class ModelC
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public long Id { get; set; }
        public Account Account { get; set; }
    }

    public class Account
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public long Id { get; set; }
        public string Description { get; set; }
    }

I don't want SQL to assign PK automatically as these are entities that will already have a unique id (ex. there is only ever 1 account with Id 2, etc..)

When I try to run the following, I get a private key violation Cannot insert duplicate key in object dbo.Account. The duplicate key value is (2).

        var context = new MyContext();

        myOrders.ToList().ForEach(p =>
        {
             context.MyOrders.AddOrUpdate(p);

        });
        context.SaveChanges();

I've tried AsNoTracking() and setting the EntityState to Modified if it's found in the table already.

This is the JSON data that is populating myOrders. myOrders is a List

[   {
    "MainModel": {
        "Id": 100,
        "ModelB": {
            "Id": 1,
            "Account": {
                "Id": 2,
                "Description":"This is a test account"
            }
        },
        "ModelC": {
            "Id": 1,
            "Account": {
                "Id": 2,
                "Description":"This is a test account"
            }
        }
    }
},
{
    "MainModel": {
        "Id": 200,
        "ModelB": {
            "Id": 5,
            "Account": {
                "Id": 2,
                "Description":"This is a test account"
            },
        }
        "ModelC": {
            "Id": 6,
            "Account": {
                "Id": 2,
                "Description":"This is a test account"
            }
        }
    }
}
}
]

Any thoughts?

1
2
12/13/2018 4:07:06 PM

Popular Answer

Firstly, if this is application code rather than migration/test setup you should avoid the use of AddOrUpdate. It is not intended to be used for general insert or update scenarios. As a general rule I don't advise passing entities around at all. Entities represent your domain, not your model. Model classes (or ViewModels) should be simple, serializable POCO classes with just the information that a view needs to consume. Passing entities around leads to complexity around re-attaching, performance issues with potential lazy loads and the simple fact you're often querying and passing more data than necessary, and security issues in that more information is passed, and in your case trusted, meaning it is relatively easy to corrupt your data source. I.e. modify an entity to change a FK reference or other data via debugging tools that you may not intend for the client to change. Your code trusts the entity coming back and simply looks to attach it and commit the change as an update. I could change anything in the object graph regardless of what you show in the UI.

The issue you are likely facing is that EF is attempting to resolve the related entities and since they aren't associated with that DBContext it is treating them as new records. You may use AddOrUpdate on the top level, but I don't believe that applies through to related entities. It doesn't automatically with Attach, so I wouldn't be surprised if it doesn't work magic with AddOrUpdate. If you need to re-attach entity graphs to a context then it can be rather cumbersome to dive through the graph and handle updates, inserts, and/or deletes. You can use a library like GraphDiff (https://github.com/zzzprojects/GraphDiff) to assist with this.

0
12/13/2018 9:52:36 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow