Two different objects with same key for entity framework does not work

c# entity-framework

Question

I am trying to insert object reference in my main object but EntityFramework will complain if I don't use its previously managed object. I simply want to avoid having a dependency on the dbContext when creating my object.

Simplified example:

class Movie {
    public ApplicationUser Owner { get;set; }
}

var myMovie = db.Movies.FirstOrDefault(m, m => m.Id = 1);
myMovie.Owner = new ApplicationUser { Id = 2 };

// I have to attach or change its state, otherwise, EF will complain the object is not complete
db.Entry(myMovie.Owner).State = EntityState.Unchanged;

Somehow, if the same ApplicationUser has been previously loaded by the context, I get this error:

Saving or accepting changes failed because more than one entity of type 'ApplicationUser' have the same primary key value. Ensure that explicitly set primary key values are unique. Ensure that database-generated primary keys are configured correctly in the database and in the Entity Framework model. Use the Entity Designer for Database First/Model First configuration. Use the 'HasDatabaseGeneratedOption" fluent API or 'DatabaseGeneratedAttribute' for Code First configuration.

How can I avoid this problem? Optimally, I would like to not have to tell the state of that new object.

1
11
10/22/2014 10:54:58 PM

Popular Answer

If you have an instance where you are only reading data and not modifying it you can use AsNoTracking() this will prevent having an attached instance of the model that your context knows about (it is essentially read only).

The following code should work even though it has retreived the same object twice.

var myMovieReadOnly = db.Movies.AsNoTracking().FirstOrDefault(m, m => m.Id = 1);

var myMovie = db.Movies.FirstOrDefault(m, m => m.Id = 1);
myMovie.Owner = new ApplicationUser { Id = 2 };

db.SaveChanges();

Another note is that AsNoTraking() can also save on performance in scenarios where you are only reading data.


Edit: Just reread and realized it is the ApplicationUser model and not the movie, but the same concept should apply with retreival of the first instance.


Edit2:

From our comments you could also do the following the prevent needing to do the lookup at all if you already know the ID:

class Movie {
    public int OwnerId { get;set; }
    public ApplicationUser Owner { get;set; }
}

var myMovie = db.Movies.FirstOrDefault(m, m => m.Id = 1);
myMovie.OwnerId = 2;
db.SaveChanges();
6
4/23/2019 7:22:05 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