diff --git a/entity-framework/core/modeling/owned-entities.md b/entity-framework/core/modeling/owned-entities.md index e7f1ed5457..dd8b99476a 100644 --- a/entity-framework/core/modeling/owned-entities.md +++ b/entity-framework/core/modeling/owned-entities.md @@ -1,9 +1,9 @@ --- title: Owned Entity Types - EF Core +description: How to configure owned entity types or aggregates when using Entity Framework Core author: AndriySvyryd ms.author: ansvyryd -ms.date: 02/26/2018 -ms.assetid: 2B0BADCE-E23E-4B28-B8EE-537883E16DF3 +ms.date: 11/06/2019 uid: core/modeling/owned-entities --- # Owned Entity Types @@ -13,7 +13,7 @@ uid: core/modeling/owned-entities EF Core allows you to model entity types that can only ever appear on navigation properties of other entity types. These are called _owned entity types_. The entity containing an owned entity type is its _owner_. -Owned entities are essentially a part of the owner and cannot exist without it, they are conceptually similar to [aggregates](https://martinfowler.com/bliki/DDD_Aggregate.html). +Owned entities are essentially a part of the owner and cannot exist without it, they are conceptually similar to [aggregates](https://martinfowler.com/bliki/DDD_Aggregate.html). This means that the owned type is by definition on the dependent side of the relationship with the owner. ## Explicit configuration @@ -68,7 +68,7 @@ To configure a different PK call `HasKey`: [!code-csharp[OwnsMany](../../../samples/core/Modeling/OwnedEntities/OwnedEntityContext.cs?name=OwnsMany)] > [!NOTE] -> Before EF Core 3.0 `WithOwner()` method didn't exist so this call should be removed. +> Before EF Core 3.0 `WithOwner()` method didn't exist so this call should be removed. Also the primary key was not discovered automatically so it always had be specified. ## Mapping owned types with table splitting @@ -80,6 +80,9 @@ You can use the `HasColumnName` method to rename those columns: [!code-csharp[ColumnNames](../../../samples/core/Modeling/OwnedEntities/OwnedEntityContext.cs?name=ColumnNames)] +> [!NOTE] +> Most of the normal entity type configuration methods like [Ignore](/dotnet/api/microsoft.entityframeworkcore.metadata.builders.ownednavigationbuilder.ignore) can be called in the same way. + ## Sharing the same .NET type among multiple owned types An owned entity type can be of the same .NET type as another owned entity type, therefore the .NET type may not be enough to identify an owned type. @@ -100,6 +103,8 @@ In this example `OrderDetails` owns `BillingAddress` and `ShippingAddress`, whic [!code-csharp[OrderStatus](../../../samples/core/Modeling/OwnedEntities/OrderStatus.cs?name=OrderStatus)] +Each navigation to an owned type defines a separate entity type with completely independent configuration. + In addition to nested owned types, an owned type can reference a regular entity, it can be either the owner or a different entity as long as the owned entity is on the dependent side. This capability sets owned entity types apart from complex types in EF6. [!code-csharp[OrderDetails](../../../samples/core/Modeling/OwnedEntities/OrderDetails.cs?name=OrderDetails)] @@ -108,7 +113,7 @@ It is possible to chain the `OwnsOne` method in a fluent call to configure this [!code-csharp[OwnsOneNested](../../../samples/core/Modeling/OwnedEntities/OwnedEntityContext.cs?name=OwnsOneNested)] -Notice the `WithOwner` call used to configure the navigation property pointing back at the owner. +Notice the `WithOwner` call used to configure the navigation property pointing back at the owner. To configure a navigation to the owner entity type that's not part of the ownership relationship `WithOwner()` should be called without any arguments. It is possible to achieve the result using `OwnedAttribute` on both `OrderDetails` and `StreetAdress`. @@ -118,6 +123,8 @@ Also unlike EF6 complex types, owned types can be stored in a separate table fro [!code-csharp[OwnsOneTable](../../../samples/core/Modeling/OwnedEntities/OwnedEntityContext.cs?name=OwnsOneTable)] +It is also possible to use the `TableAttribute` to accomplish this, but note that this would fail if there are multiple navigations to the owned type since in that case multiple entity types would be mapped to the same table. + ## Querying owned types When querying the owner the owned types will be included by default. It is not necessary to use the `Include` method, even if the owned types are stored in a separate table. Based on the model described before, the following query will get `Order`, `OrderDetails` and the two owned `StreetAddresses` from the database: @@ -135,7 +142,7 @@ Some of these limitations are fundamental to how owned entity types work, but so ### Current shortcomings -- Inheritance hierarchies that include owned entity types are not supported +- Owned entity types cannot have inheritance hierarchies - Reference navigations to owned entity types cannot be null unless they are explicitly mapped to a separate table from the owner - Instances of owned entity types cannot be shared by multiple owners (this is a well-known scenario for value objects that cannot be implemented using owned entity types) diff --git a/samples/core/Modeling/OwnedEntities/OwnedEntities.csproj b/samples/core/Modeling/OwnedEntities/OwnedEntities.csproj index d020c55673..81babe49ce 100644 --- a/samples/core/Modeling/OwnedEntities/OwnedEntities.csproj +++ b/samples/core/Modeling/OwnedEntities/OwnedEntities.csproj @@ -8,8 +8,11 @@ - - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/samples/core/Modeling/OwnedEntities/OwnedEntityContext.cs b/samples/core/Modeling/OwnedEntities/OwnedEntityContext.cs index e30ed556cd..32d3411f0b 100644 --- a/samples/core/Modeling/OwnedEntities/OwnedEntityContext.cs +++ b/samples/core/Modeling/OwnedEntities/OwnedEntityContext.cs @@ -47,12 +47,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) }); #endregion - modelBuilder.Entity().OwnsOne(p => p.OrderDetails, od => - { - od.Property("OrderId").ValueGeneratedNever(); - od.WithOwner(d => d.Order).HasForeignKey("OrderId"); - }); - #region OwnsMany modelBuilder.Entity().OwnsMany(p => p.ShippingCenters, a => {