Search code examples
c#entity-frameworkasp.net-web-apiasp.net-identityasp.net-identity-2

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"


Solution

  • 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.