3not3
3not3

Reputation: 536

mvc 5 code first userid as a Foreign Key - How to save data

Using MVC5 code first approach.

I haven't changed the user store, added a property called Name in ApplicationUser Class. So it looks like as follows : -

public class ApplicationUser : IdentityUser
{
    [Required]
    [StringLength(100)]
    public string Name { get; set; }

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        return userIdentity;
    }
}

I have a company class, which looks like below :-

public class Company
{
    public int Id { get; set; }

    [Required]
    [StringLength(255)]
    public string Name { get; set; }
}

A company will definitely has more than one user, but in my design a user can be associated with more than one company. So I have a separate class for CompanyUsers which looks as follows :-

public class CompanyUsers
{
    public int Id { get; set; }

    [Required]
    public virtual Company Company { get; set; }

    [Required]
    public virtual ApplicationUser User { get; set; }
}

Now, when I register a user, I'm setting its role and also companies that the user belongs to, but seems like the UserManager defined in the built-in code has already saved it. So after adding CompanyUsers data, when I call applicationDbContext.Savechanges() it fails as the user has already been saved in the database. Can you tell me how I can achieve it? I can do it in some other logic, like after creating a user, in a separate function assign users to company(s), but I want to know the solution in this circumstances. Also I can redesign the user store.

My modified register function in AccountController is as follows :-

[HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Register(RegisterViewModel model)
    {
        if (ModelState.IsValid)
        {
            var user = new ApplicationUser { UserName = model.Email, Email = model.Email, Name = model.Name };
            var result = await UserManager.CreateAsync(user, model.Password);
            if (result.Succeeded)
            {
                await UserManager.AddToRoleAsync(user.Id, model.Role);
                var userCompany = new CompanyUsers
                {

                    Company = _context.Companies.First(t => t.Id == model.CompanyId),
                    User = user
                };

                try
                {
                    _context.CompanyUsers.Add(userCompany);
                    _context.SaveChanges();// throws exception
                }
                catch (DbEntityValidationException dbEx)
                {
                    foreach (var validationErrors in dbEx.EntityValidationErrors)
                    {
                        foreach (var validationError in validationErrors.ValidationErrors)
                        {
                            Trace.TraceInformation("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
                        }
                    }
                }
                return RedirectToAction("UserViewAll", "Manage");
            }
            AddErrors(result);
        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

I have just started mvc code first approach, so I may not understand if you use technical jargon, thanks In Advance for your help!!!!!

Upvotes: 0

Views: 199

Answers (1)

Daniel Bendig
Daniel Bendig

Reputation: 41

Try adding the following code in the if (result.Succeeded) block:

_context.Entry(user).State = EntityState.Unchanged;

The issue appears to be that the data context in this method does not know the state of the user entity because UserManager.CreateAsync uses a separate context. The entity is attached when you assign it to the CompanyUser entity, and then this data context tries to save it as a new entity.

Upvotes: 1

Related Questions