Custom Entity Types - EF Core (2023)

  • 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 explicitlypossessionmethod oneOnModelCreatingor write the typeproperty attributeto 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 exampleDirectionis 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 attributeto 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 thepossessionmethod oneOnModelCreatingindicate that theDelivery addressProperty is an entity owned bydomainentity type and to configure additional facets if necessary.

modelBuilder.Entity<Order>().OwnsOne(p => p.ShippingAddress);

yes orDelivery addressthe property is privatedomainlike, you can use the string version ofpossessionMétodo:

modelBuilder.Entity<Order>().OwnsOne(typeof(StreetAddress), "ShippingAddress");

The above model maps to the following database schema:

Custom Entity Types - EF Core (1)

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 withpossessionor 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, theDirectionThe 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 manynoOnModelCreating.

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.possessionNote: 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 thedistributorClass.

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 centersthe navigation function will be("DistributorId", "Id")Where from"DistribuidorId"is the FK and"Identity"is a singleAnd tCourage.

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:

Custom Entity Types - EF Core (2)

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 theDirectionThe properties appear in the Orders table with the names ShippingAddress_Street and ShippingAddress_City.

You can use the...hascolumnnameto 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 addressmiShipping Addressboth 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 detailsHaveShipping AddressmiDelivery address, that's bothDirectiontypes afterOrder detailsor medetailed orderuntil

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?possessionMethod 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-ownerCall 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 attributebothOrder detailsmiDirection.

Also note theNavigationassociated. Navigation properties for property types can be set laterfor unrelated navigation properties.

The above model maps to the following database schema:

Custom Entity Types - EF Core (3)

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 tableand specify a different table name. The following example is mappedOrder detailsand 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 attributeNote, 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 theContainsmethod, although the property types are stored in a separate table. Based on the model described above, the following query is obtaineddomain,Order detailsand they both hadstreetsfrom 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 oneConjuntoDb<T>for a type of its own.
  • you can not callEntity<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.
Top Articles
Latest Posts
Article information

Author: The Hon. Margery Christiansen

Last Updated: 02/25/2023

Views: 6118

Rating: 5 / 5 (70 voted)

Reviews: 85% of readers found this page helpful

Author information

Name: The Hon. Margery Christiansen

Birthday: 2000-07-07

Address: 5050 Breitenberg Knoll, New Robert, MI 45409

Phone: +2556892639372

Job: Investor Mining Engineer

Hobby: Sketching, Cosplaying, Glassblowing, Genealogy, Crocheting, Archery, Skateboarding

Introduction: My name is The Hon. Margery Christiansen, I am a bright, adorable, precious, inexpensive, gorgeous, comfortable, happy person who loves writing and wants to share my knowledge and understanding with you.