This is MVC 5/ EF6. So I have the following classes:
public class User : IdentityUser
{
public User()
{
Levels = new List<Level>();
}
[Required, MaxLength(200)]
public string FirstName { get; set; }
[Required, MaxLength(200)]
public string LastName { get; set; }
public virtual ICollection<Level> Levels { get; set; }
}
and
public class Level
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<User> Users { get; set; }
}
In addition to regular MVC5 membership tables it creates 2 more: Levels
and UserLevels
(with User_Id and Level_Id columns). Levels
table has a static data (i.e. 1 - Excellent, 2 - Good, etc) and is kind of a library, I don't want to insert in this table.
What I'm trying to do is when user registers on the site and chooses the level it would go ahead and retrieve it from DB so that UserLevels
table is populated with new UserID
and selected LevelID
. Here is my code:
Level level = DBContext.Levels.Where(s => s.Name == model.Level.Name).SingleOrDefault();
if (level == null)
ModelState.AddModelError("", "Invalid Level.");
if (ModelState.IsValid)
{
var user = new User() {
UserName = model.UserName,
FirstName = model.FirstName,
LastName = model.LastName
};
user.Levels.Add(level);
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInAsync(user, isPersistent: false);
return RedirectToAction("Index", "Home");
}
else
{
AddErrors(result);
}
}
return View(model);
It throws an exception on this line: An entity object cannot be referenced by multiple instances of IEntityChangeTracker..
var result = await UserManager.CreateAsync(user, model.Password);
I'm guessing it has something to do with it trying to insert into Levels table the level that already exists in there? Of course it might be something else... Any advice? Thanks in advance!
If you're using
UserManager
the way 'it came out of the box' then it's probably instantiated like this:It means that if you don't provide a
UserManager
instance to theAccountController
constructor (and it's probably the case here), a newMyDbContext
is created for theUserManager
store.Yet, you have another instance of
MyDbContext
, as i can infer from this line in your code:All it means is that you have to make your
UserManager
use the same context:This way, you're creating the (only)
MyDbContext
instance first, then passing it to theUserManager
constructor (as theIUserStore<User>
).Also, you can definitely make a good use of Dependency Injection here and have the
MyDbContext
instance injected for you by a DI container and keeping your current code almost unchanged:See Tutorial (for Microsoft Unity).