Data Annotations - InverseProperty Attribute in EF 6 & EF Core

The InverseProperty attribute is used when two entities have more than one relationship. To understand the InverseProperty attribute, consider the following example of Course and Teacher entities.

public class Course
{
    public int CourseId { get; set; }
    public string CourseName { get; set; }
    public string Description { get; set; }

    public Teacher OnlineTeacher { get; set; }
}

public class Teacher
{
    public int TeacherId { get; set; }
    public string Name { get; set; }

    public ICollection<Course> OnlineCourses { get; set; }
}

In the above example, the Course and Teacher entities have a one-to-many relationship where one teacher can teach many different online courses. As per the default conventions in EF 6 and EF Core, the above example would create the following tables in the database.

inverseproperty example

Now, suppose we add another one-to-many relationship between the Teacher and Course entities as below.

public class Course
{
    public int CourseId { get; set; }
    public string CourseName { get; set; }
    public string Description { get; set; }

    public Teacher OnlineTeacher { get; set; }
    public Teacher ClassRoomTeacher { get; set; }
}

public class Teacher
{
    public int TeacherId { get; set; }
    public string Name { get; set; }

    public ICollection<Course> OnlineCourses { get; set; }
    public ICollection<Course> ClassRoomCourses { get; set; }
}

In the above example, the Course and Teacher entities have two one-to-many relationships. A Course can be taught by an online teacher as well as a class-room teacher. In the same way, a Teacher can teach multiple online courses as well as class room courses.

Here, EF API cannot determine the other end of the relationship. It will throw the following exception for the above example during migration.

Unable to determine the relationship represented by navigation property 'Course.OnlineTeacher' of type 'Teacher'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

However, EF 6 will create the following Courses table with four foreign keys.

inverseproperty example

To solve this issue, use the [InverseProperty] attribute in the above example to configure the other end of the relationship as shown below.

public class Course
{
    public int CourseId { get; set; }
    public string CourseName { get; set; }
    public string Description { get; set; }

    public Teacher OnlineTeacher { get; set; }
    public Teacher ClassRoomTeacher { get; set; }
}

public class Teacher
{
    public int TeacherId { get; set; }
    public string Name { get; set; }

    [InverseProperty("OnlineTeacher")]
    public ICollection<Course> OnlineCourses { get; set; }
    [InverseProperty("ClassRoomTeacher")]
    public ICollection<Course> ClassRoomCourses { get; set; }
}

In the above example, the [InverseProperty] attribute is applied on two collection navigation properties OnlineCourses and ClassRoomCourses to specify their related navigation property in the Course entity. So now, EF will be able to figure out corresponding foreign key names. EF 6 creates foreign keys OnlineTeacher_TeacherId and ClassRoomTeacher_TeacherId. EF Core creates OnlineTeacherTeacherId and ClassRoomTeacherTeacherId as shown below.

inverseproperty example

You can use the [ForeignKey] attribute to configure the foreign key name as shown below.

public class Course
{
    public int CourseId { get; set; }
    public string CourseName { get; set; }
    public string Description { get; set; }

    [ForeignKey("OnlineTeacher")]
    public int? OnlineTeacherId { get; set; }
    public Teacher OnlineTeacher { get; set; }

    [ForeignKey("ClassRoomTeacher")]
    public int? ClassRoomTeacherId { get; set; }
    public Teacher ClassRoomTeacher { get; set; }
}

public class Teacher
{
    public int TeacherId { get; set; }
    public string Name { get; set; }

    [InverseProperty("OnlineTeacher")]
    public ICollection<Course> OnlineCourses { get; set; }
    [InverseProperty("ClassRoomTeacher")]
    public ICollection<Course> ClassRoomCourses { get; set; }
}

The above example will result in the following tables in the database.

inverseproperty example

Thus, you can use the InverseProperty and ForeignKey attributes to configure multiple relationships between the same entities.