user2424495
user2424495

Reputation: 592

MVC one-to-many database not updated

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

Answers (2)

CodeNotFound
CodeNotFound

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

Shyju
Shyju

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

Related Questions