Colleagues, tell me.

Create a one-or-zero to one-or-zero relationship. There are reference books "users", "racers" and "coaches". Initial conditions: The user may or may not be a racer. It may or may not be a Coach. A driver may or may not be associated with a Portal User. Coach - likewise. Created such models and described the connection. Person base class will be used to store common information for coaches and racers.

 public class User { public int Id { get; set; } public string UserName { get; set; } public virtual Rider Rider { get; set; } public virtual Coach Coach { get; set; } } public class Rider : Person { public int Id { get; set; } public string RiderName { get; set; } } public class Coach : Person { public int Id { get; set; } public string CoachName { get; set; } } public class Person { public virtual User User { get; set; } } 
 b.Entity<User>() .HasOptional(u => u.Rider) .WithOptionalDependent(r => r.User) .Map(c => c.MapKey("RiderId")); b.Entity<User>() .HasOptional(u => u.Coach) .WithOptionalDependent(r => r.User) .Map(c => c.MapKey("CoachId")); 

When creating a migration, I get the error:

User: FromRole: NavigationProperty 'User' is not valid.

Type 'Coach' of FromRole 'User_Coach_Target' in AssociationType 'User_Coach' must be consistent with the type of 'Rider' on which

If you remove the inheritance from the Person class and add the User virtual property to the Coach and Rider classes, then everything is OK, the migration is generated as it should. Tell colleagues, what is the reason for this problem, how to solve it and is it worth it to do it at all?

    1 answer 1

    Your problem is that you are trying to map two parallel links into one navigation property, also located in another class. So you can not do.

    Direct error correction - create two separate User properties in successor classes.

    But, generally speaking, the data scheme is not all right with you. Can a racer be a coach? If it can, then we get two different Person objects with the same name — which is strange. If it can't, why do you have two different connections in the User class?

    In the first case (the driver can be immediately the user and the trainer) it is better to abandon inheritance and put Person into a separate table, making it mandatory:

     public class User { public virtual Person Person { get; set; } } public class Rider { public virtual Person Person { get; set; } } public class Coach { public virtual Person Person { get; set; } } public class Person { public virtual User User { get; set; } public virtual Rider Rider { get; set; } public virtual Coach Coach { get; set; } } b.Entity<Person>().HasOptional(p => p.User).WithRequired(u => u.Person); b.Entity<Person>().HasOptional(p => p.Rider).WithRequired(r => r.Person); b.Entity<Person>().HasOptional(p => p.Coach).WithRequired(c => c.Person); 

    Just be careful with the identifiers: "Optional - Required" communication is usually done on primary keys, and for this purpose all IDs, except that Person should not be auto-generated.

    In the second case, I can advise simply to combine the two fields from User into one:

     public class User { public int Id { get; set; } public string UserName { get; set; } public virtual Person Person { get; set; } } 
    • I thank, in general, it is clear. I want to clarify about the "two parallel links display in one navigation property." Why one? Used 2 different classes. Each of them is mapped on its own separate table ( DbSet<Riders> and DbSet<Coaches> are created in the data context). It turns out the connection will be between very different tables (User <-> Coach and User <-> Rider). How can inheritance break a model? - nikita
    • "It turns out the connection will be between completely different tables (User <-> Coach and User <-> Rider)." - this is the problem: it is one entity, not two different ones. - Pavel Mayorov pm