Working with relationships: Definitions and Code First Conventions

Description Article
Description

How It Works

Code First will create relationships when it sees navigation properties and, optionally, foreign key properties.

Code First requires at least one navigation property to create a relationship.

Conventions: Locating Foreign keys

Entity Framework examines a class which is attached to the context and if navigation properties are found then a search algorithm applied in order to try to discover a Foreign Key Association (See note for definition), i.e. discover if a foreign key named by convention was introduced by the developer.

The naming convention is {Target Type Key Name}, {Target Type Name} + {Target Type Key Name}, or {Navigation Property Name} + {Target Type Key Name}.

If no foreign key is located then it will automatically assume and implicitly introduce a foreign key between the entity classes at object level. At database level the correspondent FK constraint with the name {PROPERTYNAME}_[PROPERTYIdNAME] is then generated for the mapped tables.

If a foreign key key, unconventionally named, and fixed through DataAnnotation or the Fluent API exists then it will be used overriding the convention process described above.

If no foreign key is detected, and none is configured, Code First falls back to automatically
introducing one in the database.

Note: By convention, Code First is using the nullability of the foreign key property in the class to determine if the relationship is required or optional.

Conventions: Types of Relationships

Code First applies a set of rules to work out the multiplicity of each relationship. The rules use the navigation properties defined in the entity classes to determine multiplicity.

There can either be a pair of navigation properties that point to each other (bidirectional relationship) or a single navigation property (unidirectional relationship):

One-To-Many

  • If a classe contains a reference and a collection navigation property, Code First assumes a one-to-many relationship
  • Code First will also assume a one-to-many relationship if the class include a navigation property on only one side of the relationship (i.e. either the collection or the reference, but not both).

Based on this, Code First can also determine who is the dependent end (A) of the relationship (the end with the foreign key) and who is the principal end (B) (the end with the primary key):

It therefore knows that the table mapped to entity class B will need a FK pointing back to the PK of table mapped to entitiy class A.

If no foreign key property is defined in the classes and if successfully introduced by Code First, it will assume the relationship as optional:

When a foreign key property is defined by the developer and was detected in the classes, Code First uses the nullability of that property to determine if the relationship is required or optional.

 Many-To-Many
  • If a class include two collection properties, Code First will use a many-to-many relationship by default.

Code First convention will recognize the many-to-many relationship and build a JOIN table in the database with only the appropriate keys of the tables it’s joining. The keys are both primary keys of the JOIN table and foreign keys pointing to the joined tables.

Quering, adding, and removing related objects is done by using the class properties.
In the background, Entity Framework will use its knowledge of how both classes map to the database to create CRUD SQL commands that incorporate the JOIN table.

If not overrided in the configuration, this table will be named by combining the names of the classes it’s joining and then pluralizing the result.

One-To-Zero Or One 

  • If a classes include two reference properties, Code First will assume a one-to-zero or one relationship;
  • In the case of one-to-one relationships, some additional information must be provided so that Code First knows which entity is the “Principal” (correspondent table contains the primary key) and which is the “Dependent” (correspondent table contains the foreign key):

If no foreign key property is defined in the classes and if successfully introduced by Code First, it will assume the relationship as optional:

When a foreign key property is defined by the developer and was detected in the classes, Code First uses the nullability of that property to determine if the relationship is required or optional.

Cascade Delete 

By convention, Code First switches on cascade delete for required relationships.

When a cascade delete is defined, Code First will also configure a CASCADE DELETE in the database that it creates

If a specific relationship is optional, by convention, Code First won’t use cascade delete.

For the scenarios where the relationship is required but no cascade delete is allowed, the convention can be explicitly overrided and desired behavior configured with the Fluent API.
This is not supported with Data Annotations: The application code will be responsible for deleting or reassigning dependent data when necessary.

 

Querying

If no Primary Key/Foreign Key exists in the database then a JOIN operator must be used when querying otherwise sub-members can be accessed directly.

Managing Concurrency

In both Foreign Key and Independent associations, concurrency checks are based on the entity keys and other entity properties that are defined in the model.

When using the EF Designer to create a model, set the ConcurrencyMode attribute to fixed to specify that the property should be checked for concurrency.

When using Code First to define a model, use the ConcurrencyCheck attribute on properties that must be checked for concurrency. When working with Code First can the TimeStamp attribute can be used to specify that the property should be checked for concurrency. Only one timestamp property can exist in a given class. Code First maps this property to a non-nullable field (NOT NULL) in the database.

Foreign Key Associations vs Independent Associations

A relationship between two entities is characterized as a Foreign key Association when the model includes foreign properties in addition to the corresponding navigation properties.
The foreign key properties are directly mapped to FK columns in the database.

A relationship between two entities is characterized as a Independent Association when foreign key properties are not included in the model.
The association information is managed as an independent object. Relationships are tracked through object references instead of foreign key properties.

It is recommended to use Foreign key associations, i.e. include properties in the model that map to foreign keys in the database:

  • With foreign key properties included, a relationship can easealy be created or changed by modifying the foreign key value on a dependent object.

When creating or changing a relationship between two entity objects. An Independent Association will obligate a query on the database to retrieve the child object, if not in the memory:

lvParentObjectInstance.NavigationProperty = lvChildObjectInstance;

A Foreign Key Association simply use the key value:

lvParentObjectInstance.ChildPropertForeignKeyId = 3;