Tutorials Entity Framework Core Mastery
Owned Entity Types (Value Objects)
On this page
Owned Entity Types (Value Objects)
In Domain-Driven Design (DDD), a Value Object is an object that has no identity of its own (no Primary Key) and is entirely defined by its properties. A classic example is a StreetAddress. If you and I have the exact same address string, we live in the same house. EF Core supports Value Objects via Owned Entities.
1. Modeling the Value Object
First, we create the C# class for the Address. Notice it has NO Id property.
public class Address
{
public string Street { get; private set; }
public string City { get; private set; }
public string ZipCode { get; private set; }
public Address(string street, string city, string zipCode)
{
Street = street;
City = city;
ZipCode = zipCode;
}
}
2. Applying It to the Parent Entity
We use this Address type directly inside our User class.
public class User
{
public int Id { get; set; }
public string Name { get; set; }
// The complex Value Object. It is fundamentally Owned by the User.
public Address HomeAddress { get; set; }
}
3. Table Splitting (The Fluent API Magic)
If we try to run a Migration now, EF Core will panic because it doesn't know how to map Address. We must use the OwnsOne() configuration.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>(entity =>
{
// Tell EF Core that Address is completely dependent on User
entity.OwnsOne(u => u.HomeAddress, addressMap =>
{
// By default, EF Core "Table Splits". It physically flattens the Address
// properties into the main 'Users' SQL table!
addressMap.Property(a => a.Street).HasColumnName("Home_Street");
addressMap.Property(a => a.City).HasColumnName("Home_City");
});
});
}
Users containing: [Id], [Name], [Home_Street], [Home_City].
When LINQ queries the row, EF Core automatically extracts those SQL columns and hydrates them into the nested C#
Address object!
4. Interview Mastery
Q: "Why should we use an Owned Entity (Table Splitting) to store an Address, rather than just serializing the Address object to JSON and saving it in an NVARCHAR column?"
Architect Answer: "Queryability and Indexing. If you serialize the Address into a JSON string, SQL Server loses native relational awareness of those fields (unless you utilize specific SQL JSON syntax and computed columns). If you try to run `_context.Users.Where(u => u.HomeAddress.City == 'Chicago')`, a JSON string mapping will crash EF Core's LINQ translator. However, because Owned Entities utilize Table Splitting, the `City` physically exists as a standard `NVARCHAR` column in the `Users` table! That means you can write standard EF Core LINQ queries against the nested object properties, and you can even apply high-performance SQL B-Tree Indexes directly onto the `Home_City` column."