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"
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With