Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EntityFrameworks inserts already inserted related item

Im trying to create a user, then connect that user to an model called Event.

var user = new ApplicationUser { name = "test", email = "[email protected]" };
var userResult = UserManager.Create(user, "password");
if (userResult.Succeeded)
{
     SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: true);
     @event.CreatedBy = user;
     @event.CreatedById = new Guid(user.Id);
     db.Events.Add(@event);
     db.SaveChanges();
}

But db.SaveChanges() throws an validation error on the ApplicationUser model: user with the email already exists: [email protected] (even though it didnt exists before this request)

So it would seem as EF is trying to reinserted the already inserted user.

The Event model have these setters/getters

public virtual ApplicationUser CreatedBy { get; set; }
public virtual Guid CreatedById { get; set; }

And it works great if i would get the current singned in user instead of signing up a new one.

I have tried only to set @event.CreatedById and skip @event.CreatedBy, but then EF doesnt save the reference to the database.

like image 670
Marcus Brunsten Avatar asked Dec 18 '25 11:12

Marcus Brunsten


1 Answers

This line creates a new user (and probably saves it to your database):

var userResult = UserManager.Create(user, "password");

So you don't have the result you got back from the database (return value of the Add method), which is a proxy that EF knows exists in database. In fact it's a link between the database record and the object you have in memory. Then you have the following lines:

@event.CreatedBy = user;
db.Events.Add(@event);
db.SaveChanges();

You assign the user (which is a simple poco, no connection to EF whatsoever) to your event. When you add the event to the database, EF will try to create a new user again because it's not know yet, but then of course you get an error. You will have to get the user you created from the database and assign that to your event. If you would be able to change your method UserManager.Create so it also accepts a DbContext, you could pass the context, create the user and when you need the user you can use the same context again and use the Find method (which looks for objects in the context in memory, no db call) to find the user you've added.

Edit: Maybe the most simple solution in your case is to attach the user to your context:

var user = new ApplicationUser { name = "test", email = "[email protected]" };
var userResult = UserManager.Create(user, "password");
if (userResult.Succeeded)
{
    SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: true);
    db.Users.Attach(user);
    @event.CreatedBy = user;
    @event.CreatedById = new Guid(user.Id);
    db.Events.Add(@event);
    db.SaveChanges();
}

This basically tells EF that you know the object already exists in the database.

like image 156
Alexander Derck Avatar answered Dec 20 '25 01:12

Alexander Derck



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!