EF Core Owned Entity — Complete Guide
In this tutorial, you'll learn about EF Core Owned Entity. We cover key concepts, practical examples, and best practices.
Your Order has a shipping address with Street, City, ZipCode. You create a separate Address table with a foreign key, or you flatten all address fields into the Orders table. Owned entities map value objects as columns in the parent table without a separate table.
Wrong
public class Order
{
public int Id { get; set; }
public string ShippingStreet { get; set; } // Flat columns
public string ShippingCity { get; set; }
public string ShippingZip { get; set; }
}
Output: Works. But Address is not reusable. The relationship is implicit.
Or a separate table:
public class Address
{
public int Id { get; set; }
public string Street { get; set; }
// One-to-one with Order — separate table, foreign key
}
Output: Separate table and join for a value that is always loaded with the order.
Right
public class Address
{
public string Street { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
}
public class Order
{
public int Id { get; set; }
public Address ShippingAddress { get; set; } // Owned entity
}
// Configuration
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>().OwnsOne(o => o.ShippingAddress);
}
Output: Orders table has ShippingAddress_Street, ShippingAddress_City, ShippingAddress_ZipCode columns. No separate table, no join. The Address class is reusable.
Prevention
- Use
OwnsOnefor owned entities that are part of the parent (one-to-one in same table). - Use
OwnsManyfor collections of value objects (e.g., multiple phone numbers on a contact). - Use
WithOwnerfor navigation from owned to owner:entity.OwnsOne(o => o.Address).WithOwner(a => a.Order). - Use owned entities for value objects from Domain-Driven Design.
- Use
[Owned]attribute instead of Fluent API for simple cases. - Use computed columns for owned entity properties if needed.
Common Mistakes with core owned entity
- Overlapping type class instances that cause GHC to reject the program with ambiguous dispatch errors
- Non-exhaustive pattern matches that compile with warnings then crash at runtime
- Misunderstanding that
Stringis[Char]with poor performance for large text operations
These mistakes appear frequently in real-world EF code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Owned entities are used in DodaTech's order processing for address, payment info, and shipping details. For more EF Core, visit DodaTech.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro