In previous article, we have seen some basic rules about how entity framework core interprets the navigation properties and how it implicitly defines relationships based on how the properties are defined in a class.
If the EF core convention does not suit the application or coding style because of any reasons, then EF core also provides ways to explicitly configure the relationships. Another important reason why you would prefer explicitly configured relationships is – if conventions are not able to interpret the EF Core C# models properly, the ambiguity might create database entities which differ from actual intended design.
The relationships can be configured by using Fluent API or using data annotations. We are going to have a look at how this can be done.
Inverse Property Attribute
Let’s first have a look at how to specify relationships using attributes. The attribute – InversePropertyAttribute – can be annotated on navigation properties to pair up principal entity and dependent entity. Generally this approach might be preferred if there are more than one navigation properties for a pair of principal an dependent entities.
Below is a sample example showing usage of the attribute.
Foreign Key Attribute
As the name suggests, this can be used to explicitly specify the foreign key property. Foreign key is always part of dependent entity and hence this attribute should also be specified on a property in dependent entity.
Relationships Fluent API
OnModelCreating method from the derived DbContext can be used to specify relationships using Fluent API. Every configuration starts with an entity type. There are below methods that can be applied while specifying every relationships:
- HasOne, identifies reference navigation property defined on the entity, specified at the beginning of the configuration.
- HasMany, identifies collection navigation property defined on the entity, specified at the beginning of the configuration.
- WithOne, identifies inverse navigation property (which is a reference navigation property) at the other end.
- WithMany, identifies inverse navigation property (which is a collection navigation property) at the other end.
In addition to these methods, IsRequired method can be further used to specify whether the relationship is required or optional. If relationship is mandatory, then foreign key properties must have value. That means, record in dependent entity must have corresponding record in principal entity.
Other important methods that can be used for specifying relationships are:
- HasPrincipalKey, a simple or composite key can be specified if it is intended to target any property other than primary key of principal entity.
- HasForeignKey, a simple or composite key can be specified as foreign key
- HasConstraintName, to name the constraint specified
- OnDelete, this can be used to specify behavior on deleting principal entity. For example, you can specify cascaded delete option using this method.
Using all these methods, the relationships can be specified using 3 approaches:
- Fully Defined Relationships
- Single Navigation Property
- No Foreign Key Specification, only navigation properties
- No navigation properties, only navigation property
In addition, you can also specify shadow properties using Property and HasForeignKey methods.
Below is a code example showing usages of the above methods in code:
I hope you find this information useful. Let me know your thoughts.