Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Insert dependent entity with ApplicationUser

I have the following entities:

public class ApplicationUser : IdentityUser
{
    ...
    public int? StudentId { get; set; }
    public virtual Student Student { get; set; }
}

public class Student
{
    public int Id { get; set; }
    public string UserId { get; set; }
    public virtual ApplicationUser User { get; set; }
}

And I'm trying to create an new application user and student, so I'm doing this:

var user = new ApplicationUser() {
    Name = "test",
    UserName = "test",
    Student = new Student ()
};

var result = await userManager.CreateAsync(user, "test12345!");

Result is success, the two entities are inserted in database, but Student.UserId is null

How can I insert both entities and their relationship?

I tried setting student.UserId = user.Id, but then I get an exception with this message: "Unable to determine a valid ordering for dependent operations"

like image 826
Escobar5 Avatar asked Aug 29 '15 00:08

Escobar5


2 Answers

The problem and a solution are provided here One-to-one relationsip with optional dependent end using default conventions and here EF Code First - 1-to-1 Optional Relationship. But let me add something to the subject.

Your entity design creates redundancy in the ApplicationUser related db table, but more importantly, it creates a foreign key relation cycle between the two tables. Although it's technically possible to handle such a relationship, it's a maintenance nightmare and simply should be avoided.

The beauty of the EF code first approach is that you don't have to think about such things. Don't try to design your POCOs like db tables. Except for the primary key, don't use xxxId properties. Use properly configured navigation properties to express the relations between your entities and let EF take care of the db design.

With all that in mind:

First, remove StudentId property from the ApplicationUser class and UserId property from the Student class. Note that this will remove the StudentId column from the corresponding db table, so you might consider starting off with a new db or use migrations.

Then use the following configuration:

modelBuilder.Entity<ApplicationUser>()
    .HasOptional(u => u.Student)
    .WithRequired(s => s.User).Map(a => a.MapKey("UserId"));

and your problem should be solved.

like image 118
Ivan Stoev Avatar answered Nov 05 '22 02:11

Ivan Stoev


You are looking for One to (zero or one) kind of relationship between student and application user. So for one user there may or may not be a student.

In that case you do not need application user Id in student class or if you want that then that will be your base class.

modelBuilder.Entity<ApplicationUser>() 
.HasKey(t => t.StudentId); 


// Map one-to-zero or one relationship 
modelBuilder.Entity<ApplicationUser>() 
    .HasRequired(t => t.Student) 
    .WithOptional(t => t.ApplicationUser);

Instead if you are looking for one to one relationship

modelBuilder.Entity<ApplicationUser>() 
    .HasKey(t => t.StudentId); 

modelBuilder.Entity<Instructor>() 
    .HasRequired(t => t.Student) 
    .WithRequiredPrincipal(t => t.ApplicationUser);

In both the cases you may not need Id on both entities. As an end note please share the mapping class for both if possible.

like image 28
lazy Avatar answered Nov 05 '22 02:11

lazy