Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 506
jsgoupil Avatar asked Oct 22 '14 22:10

jsgoupil


People also ask

Can Entity Framework work without primary key?

Because Entity Framework is able to modify data in your database it needs a primary key to be defined in order for it to be able to uniquely identify rows.

Does Entity Framework support foreign keys?

When you change the relationship of the objects attached to the context by using one of the methods described above, Entity Framework needs to keep foreign keys, references, and collections in sync.

What has multiple properties with the key attribute composite primary keys?

The entity type Customer has multiple properties with the [Key] attribute. Composite primary keys can only be set using HasKey in OnModelCreating . Entity type Customer has the composite primary key defined with data annotations. To set the composite primary key, use fluent API.

How do I create a composite primary key in Entity Framework Core?

The only way to configure composite keys is to use the HasKey method. You specify the properties that form the composite key by passing them in as properties of an anonymous type to the HasKey method.


2 Answers

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();
like image 137
Matt Sanders Avatar answered Oct 27 '22 19:10

Matt Sanders


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

So first check if the ApplicationUser is loaded.

var newId = 2;
var newApplicationUser = db.ApplicationUsers.Local.FirstOrdefault(u => u.Id == newId)
                             ?? new ApplicationUser { Id = newId };
myMovie.Owner = newApplicationUser;
like image 44
Gert Arnold Avatar answered Oct 27 '22 21:10

Gert Arnold