When should we prefer OwnsMany over HasMany in EF core?
In Entity Framework Core (EF Core), OwnsMany
and HasMany
are two different methods used to define relationships between entities. They are used in different scenarios and have distinct implications:
HasMany
:
HasMany
is used to define a one-to-many or many-to-many relationship between two entities.- It is typically used when you have a reference from one entity to another through a navigation property, and you want to specify that there can be multiple related entities on the “many” side of the relationship.
- For example, if you have a
Customer
entity with a navigation propertyOrders
, you would useHasMany
to specify that a customer can have multiple orders. HasMany
is suitable for situations where the related entities have their own independent existence and can be queried, updated, or deleted independently of the owner entity.- example:
OwnsMany
:
OwnsMany
is used to define a relationship where one entity "owns" a collection of related entities. The owned entities do not have their own identity in the database, they are treated as part of the owner entity.- It is used for modeling complex types or value objects that are logically part of the owning entity and should not have their own separate table with a primary key.
OwnsMany
is suitable when the related entities don't have an independent identity and are conceptually owned by the parent entity. Changes to the owner entity are automatically reflected in the owned entities.
example:
In this example, the LineItems(owned)
are owned by the Order(Owner)
, and they are stored as part of the Order
record in the database without their own primary key, you can’t do any operation on LineItems without his owner Order.
The choice between using HasMany
and OwnsMany
depends on the nature of the relationship between the entities and whether the related entities should have their own identity in the database. In the case of the relationship between Order
and Customer
, it's more appropriate to use HasMany
because:
- Independence of Identity: Each order placed by a customer is a distinct entity with its own identity. Orders typically have attributes like order date, order number, and possibly more. These attributes make each order unique and distinguishable from other orders. Therefore, orders should have their own identity in the database.
- Querying and Referential Integrity: Using
HasMany
allows you to query orders independently of customers. You can retrieve all orders, filter them by various criteria, and perform operations on them without directly affecting the customer entity. Additionally, this approach allows for referential integrity constraints to be enforced, ensuring that orders are associated with valid customers.
On the other hand, OwnsMany
is typically used when the related entities are conceptually part of the owner entity and do not have their own independent identity in the database. In the case of Order
and LineItem
, OwnsMany
is appropriate because line items are part of the order and don't exist independently. They are typically embedded within the order's structure and don't have attributes that would warrant their own separate table.
To configure a collection of owned types use OwnsMany
in OnModelCreating
.
Owned types need a primary key. If there are no good candidates properties on the .NET type, EF Core can try to create one. However, when owned types are defined through a collection, it isn’t enough to just create a shadow property to act as both the foreign key into the owner and the primary key of the owned instance, as we do for OwnsOne
: there can be multiple owned type instances for each owner, and hence the key of the owner isn't enough to provide a unique identity for each owned instance.
The two most straightforward solutions to this are:
- (Uniqueness in the table scope) Defining a surrogate primary key on a new property independent of the foreign key that points to the owner. The contained values would need to be unique across all owners (e.g. if Parent {1} has Child {1}, then Parent {2} cannot have Child {1}), so the value doesn’t have any inherent meaning. Since the foreign key is not part of the primary key its values can be changed, so you could move a child from one parent to another one, however this usually goes against aggregate semantics.
A surrogate key is an artificial or synthetic key used in a database table to uniquely identify each row of data. Unlike natural keys, which are based on existing attributes or columns in the table (e.g., a person’s Social Security Number or a product’s SKU), surrogate keys are typically system-generated and have no inherent meaning or relation to the data they identify. They are solely used for the purpose of ensuring uniqueness and facilitating efficient database operations.
Key characteristics of surrogate keys include:
- Uniqueness: Surrogate keys must be unique within the table. They ensure that no two rows in the table have the same surrogate key value.
- Stability: Surrogate keys typically do not change over time. They provide a stable means of identifying a row even if other attributes or data values change.
- Independence: Surrogate keys are independent of the natural attributes of the data. They are not derived from any inherent characteristics of the entity being modeled.
- Simplicity: Surrogate keys are often simple and efficient for indexing, querying, and joining tables. They are often integers or numeric values.
Surrogate key is a system-generated identifier used to uniquely identify rows in a database table. It serves as a stable and independent means of ensuring uniqueness, simplifying data management, and improving database performance.
- (Uninquess in the parent(owner) scope)Using the foreign key and an additional property as a composite key. The additional property value now only needs to be unique for a given parent (so if Parent {1} has Child {1,1} then Parent {2} can still have Child {2,1}). By making the foreign key part of the primary key the relationship between the owner and the owned entity becomes immutable and reflects aggregate semantics better. This is what EF Core does by default.
The choice between these two solutions depends on the specific requirements and semantics of your domain model. Solution 1 with a surrogate key is more flexible in terms of moving children between parents, while Solution 2 with a composite key enforces stronger ownership and reflects the domain’s semantics more closely.
Aggregate is a pattern in Domain-Driven Design. A DDD aggregate is a cluster of domain objects that can be treated as a single unit. An example may be an order and its line-items, these will be separate objects, but it’s useful to treat the order (together with its line items) as a single aggregate. Martin Fowler