22

I knew that Inverse Property is used when you have multiple relationships between classes. but I am confused between inverse property and foreign key property since both of them are used for defining relationships.

public class PrivilegeToDbOperationTypeMap : BaseEntity
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity), Column(Order = 0)]
    public int PrivilegeToDbOperationTypeMapId { get; set; }

    [ForeignKey("privilegeLookup"), Column(Order = 1)]
    [Index("IX_PrivilegeLookupId_DbOperationLookupId", 1, IsUnique = true)]
    public int PrivilegeLookupId { get; set; }

    [ForeignKey("dbOperationTypeLookup"), Column(Order = 2)]
    [Index("IX_PrivilegeLookupId_DbOperationLookupId", 2, IsUnique = true)]
    public int DbOperationLookupId { get; set; }

    #region Navigation Properties

    public PrivilegeLookup privilegeLookup { get; set; }

    public DbOperationTypeLookup dbOperationTypeLookup { get; set; }

    [InverseProperty("privilegeToDbOperationTypeMap")]
    public ICollection<RoleToPrivilegeDbOperationTypeMap> roleToPrivilegeDbOperationTypeMaps { get; set; }

    #endregion Navigation Properties
}
Dinesh
  • 255
  • 1
  • 2
  • 14

1 Answers1

31

Foreign key attribute is used to:

  1. Indicate the name of navigation property related to given foreign key property

    // this is foreign key property with related "privilegeLookup" navigation property. Database column name will be PrivilegeLookupId
    [ForeignKey("privilegeLookup"), Column(Order = 1)]       
    public int PrivilegeLookupId { get; set; }
    // this is related navigation property
    public PrivilegeLookup privilegeLookup { get; set; }
    
  2. OR indicate the name of foreign key property for given navigation property:

    // this is foreign key property
    public int PrivilegeLookupId { get; set; }
    // this is navigation property with related foreign key property
    [ForeignKey("PrivilegeLookupId")]  
    public PrivilegeLookup privilegeLookup { get; set; }
    

It is useful when default EF code-first conventions do not apply, or apply in a way not suitable for you. Here you can see a list of EF code-first conventions.

Inverse Property attribute is used when you need to indicate that navigation property in class A is related to the same foreign key as another navigation property in class B. For example:

public class Student
{
    public int StudentID { get; set; }

    public Standard CurrentStandard { get; set; }
    public Standard PreviousStandard { get; set; }
}

public class Standard
{    
    public int StandardId { get; set; }

    public ICollection<Student> CurrentStudents { get; set; }
    public ICollection<Student> PreviousStudents { get; set; }   
}

Here we have two classes, each with two navigation properties. Our intention is to have two foreign keys in table Student, probably named CurrentStandardId and PreviousStandardId, and navigation properties of class Standard are also related to the same foreign keys (one to many relationship). However, in this case EF will not realize this without futher guidance - instead it will create 4 foreign keys. To guide it, we have to use inverse property attribute:

public class Standard
{
    public int StandardId { get; set; }

    // reference to the name of another navigation property in class Student
    [InverseProperty("CurrentStandard")]
    public ICollection<Student> CurrentStudents { get; set; }

    // reference to the name of another navigation property in class Student
    [InverseProperty("PreviousStandard")]
    public ICollection<Student> PreviousStudents { get; set; }   
}

Now EF understands our intentions and will create just two foreign keys, though the names will be not good. To also change column names, we can use foreign key attribute:

public class Student 
{
    public int StudentID { get; set; }

    public int CurrentStandardId { get; set; }
    public int PreviousStandardId { get; set; }

    [ForeignKey("CurrentStandardId")]
    public Standard CurrentStandard { get; set; }

    [ForeignKey("PreviousStandardId")]
    public Standard PreviousStandard { get; set; }
}

Long story short - EF can deduce many things based on code conventions. However when it cannot (for example when you have two foreign keys in the same class) - you have to help it using attributes from your question.

Evk
  • 98,527
  • 8
  • 141
  • 191
  • 4
    To make it complete, property `public ICollection CurrentStudents` could also be annotated with `[ForeignKey("CurrentStandardId")]`. This takes it deceptively close to `InverseProperty`, but it can only refer to a primitive property, not a reference property, like `CurrentStandard`. – Gert Arnold Nov 08 '16 at 21:58
  • 3
    It should be emphasized that the need for the InverseProperty is only when there are multiple navigation properties of the same type. If Student would only have CurrentStandard and Standard would only have CurrentStudents then EF could infer the correct relationship without denoting it with the InverseProperty. – BornToCode Jan 27 '21 at 09:43