- Article
- 8 minutes to read
With EF Core, you can model entity types that can only appear in the navigation properties of other entity types. These are calledown entity types. The entity that contains a property entity type is itsowner.
Condos are essentially a part of the owner and cannot exist without the owner, they are conceptually similarAdd. This means that the ownership entity is, by definition, on the dependent side of the ownership relationship.
Set types as related
Most providers never set entity types by convention; you must use them explicitlypossession
method oneOnModelCreating
or write the typeproperty attribute
to set the type as your own. An exception to this is the Azure Cosmos DB provider. Since Cosmos DB is a document database, the provider sets all related entity types as property by default.
In this exampleDirection
is a type without an identity property. It is used as an Order type property to specify the shipping address for a specific order.
we can use thoseproperty attribute
to treat it as its own entity when referencing another entity type:
[propiedad]public class StreetAddress{ public string Street { get; define } public string Cidade { get; definir }}
Orden de clase pública { public int Id { get; define } public StreetAddress ShippingAddress { get; definir }}
It is also possible to use thepossession
method oneOnModelCreating
indicate that theDelivery address
Property is an entity owned bydomain
entity type and to configure additional facets if necessary.
modelBuilder.Entity<Order>().OwnsOne(p => p.ShippingAddress);
yes orDelivery address
the property is privatedomain
like, you can use the string version ofpossession
Método:
modelBuilder.Entity<Order>().OwnsOne(typeof(StreetAddress), "ShippingAddress");
The above model maps to the following database schema:
Watch thecomplete sample projectfor more context.
Cima
The property entity type can be tagged as needed, seeRequired Individual DependentsFor more information.
implicit keys
Own types configured withpossession
or discovered by reference navigation always have a one-to-one relationship with the owner, so they don't need their own key values because foreign key values are unique. In the example above, theDirection
The type does not have to define a key property.
To understand how EF Core tracks these objects, it helps to know that a primary key is created aspropiedad de la sombrafor the property type. The key value of an instance of the owner type is the same as the key value of the owner instance.
Property Type Collections
To configure a collection of property types, useowns many
noOnModelCreating
.
Property types require a primary key. If there are no good candidate properties for the .NET type, EF Core can try to create one. However, when defining property types on a collection, it is not enough to simply create a hidden property that acts as the foreign key of the owner and the primary key of the owning instance, as we do.possession
Note: There can be multiple property type instances for each owner, so the owner key is not sufficient to provide a unique identity for each property instance.
The two simplest solutions for this are:
- Define a surrogate primary key for a new property, independent of the foreign key that points to the owner. Contained values should be unique across all owners (for example, if parent {1} has child {1}, parent {2} cannot have child {1}), so the value does not have a inherent meaning. Because the foreign key is not part of the primary key, its values can change, allowing you to move a child from one parent to another, but this often violates aggregate semantics.
- Using the foreign key and an additional property like a composite key. The value of the additional property now only has to be unique for a given parent (so if parent {1} has child {1,1}, 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 owning entity becomes immutable and better reflects the added semantics. EF Core does this by default.
In this example we use thedistributor
Class.
public class Distribuidor{ public int Id { get; define } public ICollection<StreetAddress> ShippingCenters { get; definir }}
By default, the primary key for the referenced property type is usedshipping centers
the navigation function will be("DistributorId", "Id")
Where from"DistribuidorId"
is the FK and"Identity"
is a singleAnd t
Courage.
How to set a different primary key invocationhas key
.
modelBuilder.Entity<Distributor>().OwnsMany( p => p.ShippingCenters, a => { a.WithOwner().HasForeignKey("OwnerId"); a.Property<int>("Id"); a.HasKey ("Identidad"); });
The above model maps to the following database schema:
Assign property types with table splitting
By default, when using relational databases, reference property types map to the same table as the owner. To do this, the table must be split into two parts: some columns are used to store owner data, and some columns are used to store owner entity data. This is a common trait known astable layout.
By default, EF Core names database columns for property entity type properties using the patternNavigation_OwnedEntityProperty. therefore theDirection
The properties appear in the Orders table with the names ShippingAddress_Street and ShippingAddress_City.
You can use the...hascolumnname
to rename these columns.
modelBuilder.Entity<Order>().OwnsOne( o => o.ShippingAddress, sa => { sa.Property(p => p.Street).HasColumnName("ShipsToStreet"); sa.Property(p => p. Ciudad).HasColumnName("ShipsToCity"); });
supervision
Most of the normal configuration methods for entity types, such asIgnorecan be accessed in the same way.
Sharing the same .NET type between multiple property types
A property entity type may be the same .NET type as another property entity type, so the .NET type may not be sufficient to identify a property type.
In these cases, the property referenced by the owner to the owner entity becomes thenavigation definitionthe type of entity you own. From EF Core's perspective, the navigation definition is part of the type's identity along with the .NET type.
For example in the following classDelivery address
miShipping Address
both are of the same .NET type,Direction
.
public class OrderDetails{ public DetailOrder Order { get; define } public billing address StreetAddress { get; define } public StreetAddress ShippingAddress { get; define }}
To understand how EF Core distinguishes tracked instances of these objects, it might help to imagine that the definition navigation has become part of the instance key along with the value of the owner key and the .NET type of the type itself. .
Nested Property Types
In this exampleOrder details
HaveShipping Address
miDelivery address
, that's bothDirection
types afterOrder details
or medetailed order
until
public class DetailOrder { public int Id { get; define } order details public order details { get; define } public status do status do order { get; define }}
public enum OrderStatus{Pending, Shipped}
Each navigation to a property type defines a separate entity type with completely separate settings.
In addition to nested property types, a property type can refer to a regular entity, which can be the owner or another entity, as long as the owning entity is on the dependent side. This feature separates custom entity types from complex types in EF6.
public class OrderDetails{ public DetailOrder Order { get; define } public billing address StreetAddress { get; define } public StreetAddress ShippingAddress { get; define }}
Configure property types
Is concatenation possible?possession
Method in a fluent call to set up this model:
modelBuilder.Entity<DetailedOrder>().OwnsOne( p => p.OrderDetails, od => { od.WithOwner(d => d.Order); od.Navigation(d => d.Order).UsePropertyAccessMode(PropertyAccessMode. Propriedade); od.OwnsOne(c => c.BillingAddress); od.OwnsOne(c => c.ShippingAddress); });
observe theco-owner
Call used to set the navigation property that points to the owner. To define navigation for the owner entity type that is not part of the owner relationshipcomOwner()
must be called without arguments.
It is also possible to obtain this result withproperty attribute
bothOrder details
miDirection
.
Also note theNavigation
associated. Navigation properties for property types can be set laterfor unrelated navigation properties.
The above model maps to the following database schema:
Store custom types in separate tables
Also, unlike complex EF6 types, ownership types can be stored in a separate table by owners. To override the convention that assigns a property type to the same table as the owner, you can simply callfor table
and specify a different table name. The following example is mappedOrder details
and their two addresses to a separate table ofdetailed order
:
modelBuilder.Entity<DetailedOrder>().OwnsOne(p => p.OrderDetails, od => { od.ToTable("OrderDetails"); });
It is also possible to use theThe table attribute
Note, however, that this will fail if there are multiple navigations to the property type, as multiple entity types would map to the same table in that case.
Query property types
Property types are included by default when querying the owner. It is not necessary to use theContains
method, although the property types are stored in a separate table. Based on the model described above, the following query is obtaineddomain
,Order details
and they both hadstreets
from the database:
var order = context.DetailedOrders.First(o => o.Status == OrderStatus.Pending);Console.WriteLine($"First pending order will ship to: {order.OrderDetails.ShippingAddress.City}");
limitations
Some of these restrictions are fundamental to how custom entity types work, others are restrictions that we may remove in future releases:
design constraints
- you can't create one
ConjuntoDb<T>
for a type of its own. - you can not call
Entity<T>()
in their own wayModelBuilder
. - Instances of custom entity types cannot be shared among multiple owners (this is a known scenario for value objects that cannot be implemented with custom entity types).
current defects
- Custom entity types cannot have inheritance hierarchies
Defects in previous versions
- In EF Core 2.x, reference navigations to owned entity types cannot be null unless they are explicitly assigned to a separate owner table.
- In EF Core 3.x, columns for owned entity types that map to the same table as the owner are always marked as nullable.