Bewerken

Share via


Introduction to relationships

This document provides a simple introduction to the representation of relationships in object models and relational databases, including how EF Core maps between the two.

Relationships in object models

A relationship defines how two entities relate to each other. For example, when modeling posts in a blog, each post is related to the blog it is published on, and the blog is related to all the posts published on that blog.

In an object-oriented language like C#, the blog and post are typically represented by two classes: Blog and Post. For example:

public class Blog
{
    public string Name { get; set; }
    public virtual Uri SiteUri { get; set; }
}
public class Post
{
    public string Title { get; set; }
    public string Content { get; set; }
    public DateTime PublishedOn { get; set; }
    public bool Archived { get; set; }
}

In the classes above, there is nothing to indicate that Blog and Post are related. This can be added to the object model by adding a reference from Post to the Blog on which it is published:

public class Post
{
    public string Title { get; set; }
    public string Content { get; set; }
    public DateOnly PublishedOn { get; set; }
    public bool Archived { get; set; }

    public Blog Blog { get; set; }
}

Likewise, the opposite direction of the same relationship can be represented as a collection of Post objects on each Blog:

public class Blog
{
    public string Name { get; set; }
    public virtual Uri SiteUri { get; set; }

    public ICollection<Post> Posts { get; }
}

This connection from Blog to Post and, inversely, from Post back to Blog is known as a "relationship" in EF Core.

Important

A single relationship can typically traversed in either direction. In this example, that is from Blog to Post via the Blog.Posts property, and from Post back to Blog via the Post.Blog property. This is one relationship, not two.

Tip

In EF Core, the Blog.Posts and Post.Blog properties are called "navigations".

Relationships in relational databases

Relational databases represent relationships using foreign keys. For example, using SQL Server or Azure SQL, the following tables can be used to represent our Post and Blog classes:

CREATE TABLE [Posts] (
    [Id] int NOT NULL IDENTITY,
    [Title] nvarchar(max) NULL,
    [Content] nvarchar(max) NULL,
    [PublishedOn] datetime2 NOT NULL,
    [Archived] bit NOT NULL,
    [BlogId] int NOT NULL,
    CONSTRAINT [PK_Posts] PRIMARY KEY ([Id]),
    CONSTRAINT [FK_Posts_Blogs_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [Blogs] ([Id]) ON DELETE CASCADE);

CREATE TABLE [Blogs] (
    [Id] int NOT NULL IDENTITY,
    [Name] nvarchar(max) NULL,
    [SiteUri] nvarchar(max) NULL,
    CONSTRAINT [PK_Blogs] PRIMARY KEY ([Id]));

In this relational model, the Posts and Blogs tables are each given a "primary key" column. The value of the primary key uniquely identifies each post or blog. In addition, the Posts table is given a "foreign key" column. The Blogs primary key column Id is referenced by the BlogId foreign key column of the Posts table. This column is "constrained" such that any value in the BlogId column of Posts must match a value in the Id column of Blogs. This match determines which blog every post is related to. For example, if the BlogId value in one row of the Posts table is 7, then the post represented by that row is published in the blog with the primary key 7.

Mapping relationships in EF Core

EF Core relationship mapping is all about mapping the primary key/foreign key representation used in a relational database to the references between objects used in an object model.

In the most basic sense, this involves:

  • Adding a primary key property to each entity type.
  • Adding a foreign key property to one entity type.
  • Associating the references between entity types with the primary and foreign keys to form a single relationship configuration.

Once this mapping is made, EF changes the foreign key values as needed when the references between objects change, and changes the references between objects as needed when the foreign key values change.

Note

Primary keys are used for more than mapping relationships. See Keys for more information.

For example, the entity types shown above can be updated with primary and foreign key properties:

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual Uri SiteUri { get; set; }

    public ICollection<Post> Posts { get; }
}
public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public DateTime PublishedOn { get; set; }
    public bool Archived { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

Tip

Primary and foreign key properties don't need to be publicly visible properties of the entity type. However, even when the properties are hidden, it is important to recognize that they still exist in the EF model.

The primary key property of Blog, Blog.Id, and the foreign key property of Post, Post.BlogId, can then be associated with the references ("navigations") between the entity types (Blog.Posts and Post.Blog). This is done automatically by EF when building a simple relationship like this, but can also be specified explicitly when overriding the OnModelCreating method of your DbContext. For example:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey(e => e.BlogId)
        .HasPrincipalKey(e => e.Id);
}

Now all these properties will behave coherently together as a representation of a single relationship between Blog and Post.

Find out more

EF supports many different types of relationships, with many different ways these relationships can be represented and configured. To jump into examples for different kinds of relationships, see:

If you are new to EF, then trying the examples linked in in the bullet points above is a good way to get a feel for how relationships work.

To dig deeper into the properties of entity types involved in relationship mapping, see:

EF models are built using a combination of three mechanisms: conventions, mapping attributes, and the model builder API. Most of the examples show the model building API. To find out more about other options, see:

Important

The model-building API is the final source of truth for the EF model--it always takes precedence over configuration discovered by convention or specified by mapping attributes. It is also the only mechanism with full fidelity to configure every aspect of the EF model.

Other topics related to relationships include:

  • Cascade deletes, which describe how related entities can be automatically deleted when SaveChanges or SaveChangesAsync is called.
  • Owned entity types use a special type of "owning" relationship that implies a stronger connection between the two types than the "normal" relationships discussed here. Many of the concepts described here for normal relationships are carried over to owned relationships. However, owned relationships also have their own special behaviors.

Tip

Refer to the glossary of relationship terms as needed when reading the documentation to help understand the terminology used.

Using relationships

Relationships defined in the model can be used in various ways. For example: