Click here to Skip to main content
15,867,993 members
Articles / Programming Languages / C#

Reducing Complexity using Entity Framework Core Owned Types

Rate me:
Please Sign up or sign in to vote.
4.56/5 (4 votes)
21 Mar 2021CPOL2 min read 5.8K   8   2
Group fields that you do not want to appear as a reference, in a separate type using EF Core owned typed
In this post, we will take a look at EF Core’s owned types that allow you to group fields which you do not want to appear as a reference, in a separate type.

I came across a very nice feature of Entity Framework Core that I would like to share with you, it is the owned types.

EF Core’s owned types allow you to group fields, that you do not want to appear as a reference, in a separate type.

Let us start by an example. Suppose you have this model. You have Customer and Order and both have fields for an address.

C#
class Customer
{
  [Key]
  public long CustomerID { get; set; }
  public string Name { get; set; }

  public string Street { get; set; }
  public string City { get; set; }
  public string State { get; set; }
}
class Order
{
  [Key]
  public long OrderID { get; set; }
  public bool IsShipped { get; set; }

  public string Street { get; set; }
  public string City { get; set; }
  public string State { get; set; }
}

You can easily refactor the previous model by extracting the address fields to a new table and reference that table in your Customer and Order tables.

C#
class Address
{
  [Key]
  public long AddressID { get; set; }
  public string Street { get; set; }
  public string City { get; set; }
  public string State { get; set; }
}

But what if you want to keep the three address fields inside Customer and Order, and you do want to refactor the code and reduce complexity and duplication, what you are going to do? The answer is in owned entities.

You can update your Address class and remove its key field and include a reference in Customer and Order as follows:

C#
class Address
{
  public string Street { get; set; }
  public string City { get; set; }
  public string State { get; set; }
}
class Customer
{
  [Key]
  public long CustomerID { get; set; }
  public string Name { get; set; }

  public Address Address { get; set; }
}
class Order
{
  [Key]
  public long OrderID { get; set; }
  public bool IsShipped { get; set; }

  public Address Address { get; set; }
}

Finished? Not yet. You cannot leave your code like this as no entity can be defined without a primary key. Actually, you will get this error if you try to apply your changes to the database.

Image 1

The next update that we need to do is in the data context itself. We can use the Fluent API to give a hint of how our model will work.

C#
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
  base.OnModelCreating(modelBuilder);

  modelBuilder.Entity<Customer>().OwnsOne(a => a.Address);
  modelBuilder.Entity<Order>().OwnsOne(a => a.Address);
}

Now we can apply our model to the database and watch the magic happen!

Image 2

Our update looks very promising; however, we have a very small issue here, no one likes those “Address_” prefixes!

The answer is in Fluent API again.

C#
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
  base.OnModelCreating(modelBuilder);

  modelBuilder.Entity<Customer>().OwnsOne(a => a.Address, add=>
  {
    add.Property(p => p.Street).HasColumnName(nameof(Address.Street));
    add.Property(p => p.City).HasColumnName(nameof(Address.City));
    add.Property(p => p.State).HasColumnName(nameof(Address.State));
  });
  modelBuilder.Entity<Order>().OwnsOne(a => a.Address);
}

After applying the previous code, you can see the difference between the two generated tables:

Image 3

One little thing to mention is that you can exclude a property form being mapped by using the Ignore method:

C#
add.Ignore(p => p.State);

And if you do not like the Fluent API approach, you can simply decorate the Address class with OwnedAttribute attribute, however, this will not allow you to customize field names and other properties.

C#
[Owned]
class Address
{
  public string Street { get; set; }
  public string City { get; set; }
  public string State { get; set; }
}

Another thing to mention is that you can create a table for the owned entity using the ToTable method:

C#
modelBuilder.Entity<Customer>().OwnsOne(a => a.Address, add=>
{
  add.Property(p => p.Street).HasColumnName(nameof(Address.Street));
  add.Property(p => p.City).HasColumnName(nameof(Address.City));
  add.Property(p => p.State).HasColumnName(nameof(Address.State));

  add.ToTable("CustomerAddress");
});

And that would create a one-to-one relationship between Customer and the newly generated, CustomerAddress.

Image 4

The final thing here is that you can create a one-to-many relationship by using OwnsMany method:

C#
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
  base.OnModelCreating(modelBuilder);

  modelBuilder.Entity<Customer>().OwnsMany(a => a.Address);
  modelBuilder.Entity<Order>().OwnsOne(a => a.Address);
}

You also need to update the Customer entity to match the one-to-many relationship:

C#
class Customer
{
  [Key]
  public long CustomerID { get; set; }
  public string Name { get; set; }

  public List<Address> Address { get; set; }
}

The result is as follows:

Image 5

History

  • 21st March, 2021: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead
Egypt Egypt
Mohammad Elsheimy is a developer, trainer, and technical writer currently hired by one of the leading fintech companies in Middle East, as a technical lead.

Mohammad is a MCP, MCTS, MCPD, MCSA, MCSE, and MCT expertized in Microsoft technologies, data management, analytics, Azure and DevOps solutions. He is also a Project Management Professional (PMP) and a Quranic Readings college (Al-Azhar) graduate specialized in Quranic readings, Islamic legislation, and the Arabic language.

Mohammad was born in Egypt. He loves his machine and his code more than anything else!

Currently, Mohammad runs two blogs: "Just Like [a] Magic" (http://JustLikeAMagic.com) and "مع الدوت نت" (http://WithdDotNet.net), both dedicated for programming and Microsoft technologies.

You can reach Mohammad at elsheimy[at]live[dot]com

Comments and Discussions

 
QuestionImages? Pin
Klaus Luedenscheidt21-Mar-21 19:12
Klaus Luedenscheidt21-Mar-21 19:12 
AnswerRe: Images? Pin
Mohammad Elsheimy21-Mar-21 20:18
Mohammad Elsheimy21-Mar-21 20:18 
It has been fixed. Thanks for informing me Smile | :)
Mohammad Elsheimy

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.