Owned Entity Types in Entity Framework Core

Owned Entity Types in Entity Framework Core

Owned Entity Types are those entities that can be associated with another entity only. They cannot be used separately, the other entity to which the owned entity is associated is known as it’s owner. The owned enttity has a one-to-one relationship with the owner so they can be called as the dependents of the owner.

Example of Owned Entity Types

Consider an example where a New Delhi based company hires people from all over India. These employees will have 2 addresses – permanent and current. Current address will be in New Delhi itself, that is the address where an employee is staying in Delhi. While a permanent address of an employee will be the address of his/her family house, the family house can be in another city like Mumbai, Kanpur, Lucknow, etc.

Here we can define an Owned Entity Type for the Employee Address as shown in the code below.

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Address Current { get; set; }
    public Address Permanent { get; set; }
}

[Owned]
public class Address
{
    public string House { get; set; }
    public string Street { get; set; }
    public string City { get; set; }
}

The Address entity is the Owned entity of “Employee” entity and is it’s owner. An Owned entity should have [Owned] attribute defined over them.

We can also use OwnsOne method in OnModelCreating to configure an Owned entity as shown below.

modelBuilder.Entity<Employee>().OwnsOne(a => a.Address);

It should also be noted that we do not need to define a primary key for an Owned Entity i.e. public string House { get; set; } since Entity Framework Core will automatically assign a shadow property that will be used as it’s primary key.

On applying the migrations, the Employee table will be created along with the Address fields as shown below:

CREATE TABLE [dbo].[Employee] (
    [Id]               INT            IDENTITY (1, 1) NOT NULL,
    [Name]             NVARCHAR (MAX) NULL,
    [Current_House]    NVARCHAR (MAX) NULL,
    [Current_Street]   NVARCHAR (MAX) NULL,
    [Current_City]     NVARCHAR (MAX) NULL,
    [Permanent_House]  NVARCHAR (MAX) NULL,
    [Permanent_Street] NVARCHAR (MAX) NULL,
    [Permanent_City]   NVARCHAR (MAX) NULL,
    CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED ([Id] ASC)
);

Owned Entity Database Table

Notice the Owned entity is saved in the same table of the Onwer (i.e. Employee table) and the fields are given names in the format of “Owner field name_Owned field name” like [Current_House], [Permanent_House], etc.

Owned entity columns will be included by default whenever the owner is queried. Below code is querying details of an employee with id 10. It will also provide Owned enttity fields with it.

var emp = await context.Employee.FirstAsync(o => o.Id == 1);
var currentCity = emp.Current.City;
var permanentCity = emp.Permanent.City;

Renaming Columns with HasColumnName

The HasColumnName method can be used to rename the columns of the Owned entity types as show below.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Employee>().OwnsOne(
        o => o.Current,
        sa =>
        {
            sa.Property(p => p.Street).HasColumnName("House_Current");
            sa.Property(p => p.Street).HasColumnName("Street_Current");
            sa.Property(p => p.City).HasColumnName("City_Current");
        });

    modelBuilder.Entity<Employee>().OwnsOne(
        o => o.Permanent,
        sa =>
        {
            sa.Property(p => p.Street).HasColumnName("House_Permanent");
            sa.Property(p => p.Street).HasColumnName("Street_Permanent");
            sa.Property(p => p.City).HasColumnName("City_Permanent");
        });
}

This will create the Employee table with the following defination.

CREATE TABLE [dbo].[Employee] (
    [Id]               INT            IDENTITY (1, 1) NOT NULL,
    [Name]             NVARCHAR (MAX) NULL,
    [House_Current]    NVARCHAR (MAX) NULL,
    [Street_Current]   NVARCHAR (MAX) NULL,
    [City_Current]     NVARCHAR (MAX) NULL,
    [House_Permanent]  NVARCHAR (MAX) NULL,
    [Street_Permanent] NVARCHAR (MAX) NULL,
    [City_Permanent]   NVARCHAR (MAX) NULL,
    CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED ([Id] ASC)
);
Entity Framework Core deals with object values with Value Converters and Value Comparers. The Value Converters helps in converting object values from one type to another while Value Comparers helps in comparing the object values needed for change tracking, custom comparision codes, etc. Learn all this in the article – Value Converters and Comparers in Entity Framework Core.

Collection of Owned Entity Types

Recall that the Owned entity does not require to define a primary key since Entity Framework Core will provide a shadow property that will be used as the primary key for the owned entity. This will work everywhere but not when working with collection of owned entity types.

The reason for this is when dealing with collection of Owned entity, it isn’t enough to just create a shadow property which will act both as the foreign key to the owner and the primary key of the owned. Here we will have multiple instances of owned types for each owner, and hence the key of the owner, which is the shadow property created by Entity Framework Core, isn’t enough to provide a unique identity for each owned instance.

See the below example where a distributor has a collection of owned entity type called Address.

public class Distributor
{
    public int Id { get; set; }
    public ICollection<Address> Addr { get; set; }
}

[Owned]
public class Address
{
    public int Id { get; set; }
    public string OfficeName { get; set; }
    public string Street { get; set; }
    public string City { get; set; }
    public int OwnerId { get; set; }
}

We configure the Owned entity for the foreign and primary keys in the OnModelCreating as shown below.

modelBuilder.Entity<Distributor>().OwnsMany(
    p => p.Addr, a =>
    {
        a.WithOwner().HasForeignKey("OwnerId");
        a.HasKey("Id");
    });

Storing Owned types in separate Table

By default, owned types will be stored in the same table along with the owner. We can overried this to store owned entity in separate table.

The below configuration will store Address owned entity to another database table called AddressOwned.

modelBuilder.Entity<Distributor>().OwnsOne(p => p.Addr, od => { od.ToTable("AddressOwned"); });
Conclusion

In this tutorial we learned what is an Owned Entity type, how to work with them and how to configure them based on our likings. I hope you understood the topic and if you still have a confusion you can comment below to ask your doubts.

SHARE THIS ARTICLE

  • linkedin
  • reddit
yogihosting

ABOUT THE AUTHOR

I hope you enjoyed reading this tutorial. If it helped you then consider buying a cup of coffee for me. This will help me in writing more such good tutorials for the readers. Thank you. Buy Me A Coffee donate

Leave a Reply

Your email address will not be published. Required fields are marked *