0

I am trying to insert a value from the standard MVC registration form (namely the email field), this will be the primary key and FK in another table. My student table only contains email, I want to insert the same value(email field) that is submitted at registration to the aspnetusers table. I have written this code so far:

var student = new Student { email = model.Email }; 

assigning the value and then

db.Students.Add(student);
db.SaveChanges(); 

to perform the action, I assume this is done in the Registration controller. Please advise if I have placed it in the wrong section. I am currently getting a

Please see code below:

AccountController.cs

public async Task<ActionResult> Register(RegisterViewModel model)
    {
        if (ModelState.IsValid)
        {
            var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
            var student = new Student { email = model.Email };
            var result = await UserManager.CreateAsync(user, model.Password);
            if (result.Succeeded)
            {

                string callbackUrl = await SendEmailConfirmationTokenAsync(user.Id, "Confirm your account");


                ViewBag.Message = "Check your email and confirm your account, you must be confirmed "
                                + "before you can log in.";
                db.Students.Add(student);
                db.SaveChanges();
                return View("Info");

                //return RedirectToAction("Index", "Home");
            }
            AddErrors(result);
        }

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

Student.cs

 public class Student
{
    [Key, ForeignKey("User")]
    public string email { get; set; }
    public virtual ApplicationUser User { get; set; }
}
Newbie
  • 61
  • 3
  • 10

3 Answers3

2

Your foreign key here is on the implicit table colum User_Id, which is non-nullable by default, and you've not set a value for User to get the value from. It seems like you're wanting to use the email as the foreign key, instead, but that's not how things work. A foreign key references the primary key of the related table, which for AspNetUsers is Id, not Email. Even if you could do it this way, it would be an extremely bad idea. Email is NVARCHAR(MAX), which cannot be indexed.

Long and short, the quick fix is to simply set User on your student instance:

var student = new Student { email = model.Email, User = user };

However, it would be far better to implement inheritance here. A student is a user, so set it up that way:

public class Student : ApplicationUser

Then, you don't need any of this at all. By creating a Student there's automatically an associated ApplicationUser, because it is an ApplicationUser.

UPDATE

When inheriting, just remember that you're inheriting all the properties on ApplicationUser, so you don't need to add Email and such again. If you pull the user from the context, you can use OfType<Student>, for example, to only get students. If you use the default implementation of ApplicationUserManager, it will always return ApplicationUser instances, though. However, since it inherits from UserManager<TUser>, you can simply modify that class to remain generic:

public class ApplicationUserManager<TUser> : UserManager<TUser>
    where TUser : ApplicationUser

To avoid having to modify any existing code, you can declare a non-generic version of the class as well:

public class ApplicationUserManager : ApplicationUserManager<ApplicationUser>
{
    public ApplicationUserManager(UserStore<ApplicationUser> store)
        : base(store)
    {
    }
}

Then, you can construct different instances of ApplicationUserManager to work with the different types of users you have. Since ApplicationUser is your base type, you should use that if you need to work with all users, such as for the purposes of general sign in.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • I tried the quick fix and it did not work, gave an error Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. when it reached db.SaveChanges();, I am more interested in the inheritance way thou, after doing public class Student : ApplicationUser will I need to change anything else? – Newbie Jun 16 '16 at 18:17
  • Also I would like to be when someone registers based on their email it determines if they are a student or a lecturer, hence why I was taking that approach. Is that possible with going ahead with inheritance? – Newbie Jun 16 '16 at 18:24
  • Thanks Chris, I will give that a go and if I have too much problem, I think I might take another approach by removing the relationship between aspnetusers and students with the foreign key constraint. I will then place the email field insertion into the student table after the results have been successful and enters into that IF statement block, I will perform the action there. That will also get the same job done that I want. – Newbie Jun 17 '16 at 15:29
0

If student.email is a FK,then email must be exist in db in order to add new student

Mehmet
  • 739
  • 1
  • 6
  • 17
0

Student.cs is not correct. Foreign key points to a PRIMARY KEY in another table.

You can edit Student.cs like this:

public class Student
{
    [Key]
    public int StudentId { get; set; }

    //Foreign key for User
    [ForeignKey("User")]
    public int UserId { get; set; }
    public virtual ApplicationUser User { get; set; }
}

and if email is unique check it on the user table when register like this:

public async Task<ActionResult> Register(RegisterViewModel model)
{
    if (ModelState.IsValid)
    {
     var checkEMail = db.AspNetUsers.Where(a=>a.Email == model.Email).FirstOrDefault();
     if(checkEMail != null)
      {
           //Email is not valid
      }
     else
     {              
            var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
            var student = new Student { email = model.Email };
            var result = await UserManager.CreateAsync(user, model.Password);
            if (result.Succeeded)
            {

                string callbackUrl = await SendEmailConfirmationTokenAsync(user.Id, "Confirm your account");


                ViewBag.Message = "Check your email and confirm your account, you must be confirmed "
                                + "before you can log in.";
                db.Students.Add(student);
                db.SaveChanges();
                return View("Info");

                //return RedirectToAction("Index", "Home");
            }
            AddErrors(result);
      }

}
Ali Soltani
  • 9,589
  • 5
  • 30
  • 55