Reputation: 592
I have added an ApplicationCompany
class to my MVC project like this:
public class ApplicationCompany
{
public Guid Id { get; set; }
public String Name { get; set; }
public virtual List<ApplicationUser> Users { get; set; }
public ApplicationCompany()
{
Id = Guid.NewGuid();
Users = new List<ApplicationUser>();
}
}
In the ApplicationUser
class I have added:
public virtual ApplicationCompany Company { get; set; }
Now, when I debug an instance of ApplicationUser
, I can see it has the Company
property, and I can see the ApplicationCompany
table in my database. When a user registers, I'd like to add a Company
linked to them. I am doing the following but it is not saving the company:
using (var context = new ApplicationDbContext())
{
if (ModelState.IsValid)
{
var user = new ApplicationManager
{
UserName = model.Email,
Email = model.Email
};
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
var company = new ApplicationCompany();
user.Company = company;
context.SaveChanges();
...
}
}
}
Any ideas why?
Upvotes: 1
Views: 70
Reputation: 23200
The DbContext
instance you use into the if (result.Succeeded)
block doesn't know anything about the user
instance you just set before calling context.SaveChanges()
. Modify your code by attaching user
instance into the context or just changing the state of the user
to EntityState.Modified
.
if (result.Succeeded)
{
var company = new ApplicationCompany();
user.Company = company;
context.Entry(user).State = EntityState.Modified;
context.Entry(company).State = EntityState.Added;
context.SaveChanges();
}
Edit 1:
Attaching an entity of type 'ApplicationUser' failed because another entity of the same type already has the same primary key value
Because another context own the user instance, then you must instantiate the DbContext
into the if
block (don't forget to suppress the root instance you create at the start of your method) like this:
if (result.Succeeded)
{
using (var context = new ApplicationDbContext())
{
var company = new ApplicationCompany();
user.Company = company;
context.Entry(user).State = EntityState.Modified;
context.Entry(company).State = EntityState.Added;
context.SaveChanges();
}
}
Edit 2: Overriding CreateAsync
method in ApplicationUserManager
class
The better approcach, IMHO, is to oveeride CreateAsync
method in ApplicationUserManager
class. by doing that you don't need to add the company updates into your controller's action.
public class ApplicationUserManager : UserManager<ApplicationUser>
{
// ...
public override async Task<IdentityResult> CreateAsync(ApplicationUser user, string password)
{
var company = new ApplicationCompany();
user.Company = company;
return await base.CreateAsync(user, password);
}
}
Upvotes: 1
Reputation: 218722
The problem is that, you are using a different DbContext object to insert the User than the one you are using to insert the company. You should be using the same DbContext object.
Change your UserManager.CreateAsync
method to accept the DbContext object and use it there to add the new user
public Task<SomeDTO> CreateAsync(ApplicationDbContext db, ApplicationUser user,
string password)
{
//to do : Set the password
//Use db to add the new User
db.ApplicationUsers.Add(user);
await db.SaveChangesAsync();
// to do : return something
}
And when you call it from your action method, make sure to pass the DbContext.
var result = await UserManager.CreateAsync(context,user, model.Password);
That should fix your problem.
Upvotes: 0