Types d’entité détenusOwned Entity Types

Note

Cette fonctionnalité est une nouveauté dans EF Core 2.0.This feature is new in EF Core 2.0.

EF Core vous permet aux types d’entité de modèle qui peuvent apparaître uniquement sur les propriétés de navigation d’autres types d’entités.EF Core allows you to model entity types that can only ever appear on navigation properties of other entity types. Ils sont appelés types d’entités détenus.These are called owned entity types. L’entité qui contient un type d’entité détenu est son propriétaire.The entity containing an owned entity type is its owner.

Configuration expliciteExplicit configuration

La propriété entité types sont jamais incluses par EF Core dans le modèle par convention.Owned entity types are never included by EF Core in the model by convention. Vous pouvez utiliser la OwnsOne méthode dans OnModelCreating ou annotez le type avec OwnedAttribute (nouveau dans EF Core 2.1) pour configurer le type comme un type détenu.You can use the OwnsOne method in OnModelCreating or annotate the type with OwnedAttribute (new in EF Core 2.1) to configure the type as an owned type.

Dans cet exemple, StreetAddress est un type avec aucune propriété d’identité.In this example, StreetAddress is a type with no identity property. Il est utilisé comme propriété du type Order pour spécifier l’adresse d’expédition d’une commande particulière.It is used as a property of the Order type to specify the shipping address for a particular order.

Nous pouvons utiliser la OwnedAttribute pour le traiter comme une entité détenue lorsque référencé depuis un autre type d’entité :We can use the OwnedAttribute to treat it as an owned entity when referenced from another entity type:

[Owned]
public class StreetAddress
{
    public string Street { get; set; }
    public string City { get; set; }
}
public class Order
{
    public int Id { get; set; }
    public StreetAddress ShippingAddress { get; set; }
}

Il est également possible d’utiliser le OwnsOne méthode dans OnModelCreating pour spécifier que le ShippingAddress propriété est une entité appartenant à de la Order type d’entité et de configurer des facettes supplémentaires si nécessaire.It is also possible to use the OwnsOne method in OnModelCreating to specify that the ShippingAddress property is an Owned Entity of the Order entity type and to configure additional facets if needed.

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

Si le ShippingAddress propriété est privée dans le Order type, vous pouvez utiliser la version de chaîne de la OwnsOne méthode :If the ShippingAddress property is private in the Order type, you can use the string version of the OwnsOne method:

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

Consultez le exemple complet de projet pour plus de contexte.See the full sample project for more context.

Clés implicitesImplicit keys

Configuré avec des types détenus OwnsOne ou découverts grâce à une navigation de référence ont toujours une relation un à un avec le propriétaire, par conséquent, ils n’ont pas leurs propres valeurs de clés que les valeurs de clé étrangères sont uniques.Owned types configured with OwnsOne or discovered through a reference navigation always have a one-to-one relationship with the owner, therefore they don't need their own key values as the foreign key values are unique. Dans l’exemple précédent, le StreetAddress type n’a pas besoin de définir une propriété de clé.In the previous example, the StreetAddress type does not need to define a key property.

Pour comprendre comment EF Core effectue le suivi de ces objets, il est utile de considérer qu’une clé primaire est créée comme un occulter la propriété pour le type détenu.In order to understand how EF Core tracks these objects, it is useful to think that a primary key is created as a shadow property for the owned type. La valeur de la clé d’une instance du type détenu sera identique à la valeur de la clé de l’instance de propriétaire.The value of the key of an instance of the owned type will be the same as the value of the key of the owner instance.

Collections de types détenusCollections of owned types

Note

Cette fonctionnalité est une nouveauté dans EF Core 2.2.This feature is new in EF Core 2.2.

Pour configurer une collection de types détenus OwnsMany doit être utilisé dans OnModelCreating.To configure a collection of owned types OwnsMany should be used in OnModelCreating. Toutefois la clé primaire ne sera pas configurée par convention, donc il doit être spécifié explicitement.However the primary key will not be configured by convention, so it need to be specified explicitly. Il est courant d’utiliser une clé complexe pour ces types d’entités incorporant la clé étrangère pour le propriétaire et une propriété unique supplémentaire qui peut également être dans l’état de clichés instantanés :It is common to use a complex key for these type of entities incorporating the foreign key to the owner and an additional unique property that can also be in shadow state:

modelBuilder.Entity<Distributor>().OwnsMany(p => p.ShippingCenters, a =>
{
    a.HasForeignKey("DistributorId");
    a.Property<int>("Id");
    a.HasKey("DistributorId", "Id");
});

Mappage de types avec fractionnement de table détenuMapping owned types with table splitting

Lorsque vous utilisez relationnelles bases de données, par référence de la convention détenus types sont mappés à la même table que le propriétaire.When using relational databases, by convention reference owned types are mapped to the same table as the owner. Cela nécessite de fractionnement de la table en deux : certaines colonnes seront utilisées pour stocker les données du propriétaire, et certaines colonnes seront utilisées pour stocker les données de l’entité détenue.This requires splitting the table in two: some columns will be used to store the data of the owner, and some columns will be used to store data of the owned entity. Il s’agit d’une fonctionnalité commune appelée fractionnement de table.This is a common feature known as table splitting.

Conseil

Détenus types stockés avec le fractionnement de table peuvent être utilisé de la même façon pour les types complexes comment sont utilisées dans EF6.Owned types stored with table splitting can be used similarly to how complex types are used in EF6.

Par convention, EF Core nommera les colonnes de la base de données pour les propriétés du type d’entité détenu suivant le modèle Navigation_OwnedEntityProperty.By convention, EF Core will name the database columns for the properties of the owned entity type following the pattern Navigation_OwnedEntityProperty. Par conséquent le StreetAddress propriétés s’affichent dans la table « Orders » avec les noms « ShippingAddress_Street » et « ShippingAddress_City ».Therefore the StreetAddress properties will appear in the 'Orders' table with the names 'ShippingAddress_Street' and 'ShippingAddress_City'.

Vous pouvez ajouter la HasColumnName méthode pour renommer ces colonnes :You can append the HasColumnName method to rename those columns:

modelBuilder.Entity<Order>().OwnsOne(
    o => o.ShippingAddress,
    sa =>
    {
        sa.Property(p => p.Street).HasColumnName("ShipsToStreet");
        sa.Property(p => p.City).HasColumnName("ShipsToCity");
    });

Partage le même type .NET parmi plusieurs types détenusSharing the same .NET type among multiple owned types

Type d’entité détenu peut être du même type .NET en tant qu’un autre type d’entité détenu, par conséquent, le type .NET peuvent ne pas suffire pour identifier un type détenu.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.

Dans ce cas, la propriété qui pointe du propriétaire à l’entité détenue devient le définition navigation du type d’entité détenu.In those cases, the property pointing from the owner to the owned entity becomes the defining navigation of the owned entity type. Du point de vue d’EF Core, la navigation de définition fait partie de l’identité du type en même temps que le type .NET.From the perspective of EF Core, the defining navigation is part of the type's identity alongside the .NET type.

Par exemple, dans la classe suivante ShippingAddress et BillingAddress sont tous deux du même type .NET, StreetAddress:For example, in the following class ShippingAddress and BillingAddress are both of the same .NET type, StreetAddress:

public class OrderDetails
{
    public DetailedOrder Order { get; set; }
    public StreetAddress BillingAddress { get; set; }
    public StreetAddress ShippingAddress { get; set; }
}

Pour comprendre comment EF Core distinguera suivies des instances de ces objets, il peut être utile de considérer que la navigation définie est devenue partie de la clé de l’instance en même temps que la valeur de la clé du propriétaire et le type .NET du type détenu.In order to understand how EF Core will distinguish tracked instances of these objects, it may be useful to think that the defining navigation has become part of the key of the instance alongside the value of the key of the owner and the .NET type of the owned type.

Types détenus imbriquésNested owned types

Dans cet exemple OrderDetails possède BillingAddress et ShippingAddress, qui sont toutes deux StreetAddress types.In this example OrderDetails owns BillingAddress and ShippingAddress, which are both StreetAddress types. OrderDetails est alors détenu par le type DetailedOrder.Then OrderDetails is owned by the DetailedOrder type.

public class DetailedOrder
{
    public int Id { get; set; }
    public OrderDetails OrderDetails { get; set; }
    public OrderStatus Status { get; set; }
}
public enum OrderStatus
{
    Pending,
    Shipped
}

Outre les types détenus imbriqués, un type détenu peut référencer une entité normale, il peut être le propriétaire ou une autre entité tant que l’entité détenus est sur le côté dépendant.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. Cette fonctionnalité définit les types d’entité détenus en dehors des types complexes dans EF6.This capability sets owned entity types apart from complex types in EF6.

public class OrderDetails
{
    public DetailedOrder Order { get; set; }
    public StreetAddress BillingAddress { get; set; }
    public StreetAddress ShippingAddress { get; set; }
}

Il est possible de chaîner les OwnsOne méthode dans un appel fluent afin de configurer ce modèle :It is possible to chain the OwnsOne method in a fluent call to configure this model:

modelBuilder.Entity<DetailedOrder>().OwnsOne(p => p.OrderDetails, od =>
{
    od.OwnsOne(c => c.BillingAddress);
    od.OwnsOne(c => c.ShippingAddress);
});

Il est également possible de réaliser la même chose à l’aide OwnedAttribute sur les deux OrderDetails et StreetAdress.It is also possible to achieve the same thing using OwnedAttribute on both OrderDetails and StreetAdress.

Stockage des types détenus dans des tables distinctesStoring owned types in separate tables

Également Contrairement aux types complexes d’EF6, types détenus peuvent être stockées dans une table distincte du propriétaire.Also unlike EF6 complex types, owned types can be stored in a separate table from the owner. Pour substituer la convention qui mappe un type détenu à la même table en tant que le propriétaire, vous pouvez simplement appeler ToTable et fournir un autre nom de table.In order to override the convention that maps an owned type to the same table as the owner, you can simply call ToTable and provide a different table name. L’exemple suivant mappe OrderDetails et ses deux adresses dans une table distincte de DetailedOrder:The following example will map OrderDetails and its two addresses to a separate table from DetailedOrder:

modelBuilder.Entity<DetailedOrder>().OwnsOne(p => p.OrderDetails, od =>
{
    od.OwnsOne(c => c.BillingAddress);
    od.OwnsOne(c => c.ShippingAddress);
    od.ToTable("OrderDetails");
});

Interrogation des types détenusQuerying owned types

Quand le propriétaire fait l’objet d’une interrogation, les types détenus sont inclus par défaut.When querying the owner the owned types will be included by default. Il n’est pas nécessaire d’utiliser le Include (méthode), même si les types détenus sont stockées dans une table distincte.It is not necessary to use the Include method, even if the owned types are stored in a separate table. Selon le modèle décrit précédemment, la requête suivante obtiendra Order, OrderDetails et les deux détenus StreetAddresses à partir de la base de données :Based on the model described before, the following query will get Order, OrderDetails and the two owned StreetAddresses 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}");

LimitationsLimitations

Certaines de ces restrictions sont fondamentaux pour comment détenu travail de types d’entité, mais d’autres sont des restrictions que nous pouvons être en mesure de supprimer dans les futures versions :Some of these limitations are fundamental to how owned entity types work, but some others are restrictions that we may be able to remove in future releases:

Restrictions par conceptionBy-design restrictions

  • Vous ne pouvez pas créer un DbSet<T> pour un type détenuYou cannot create a DbSet<T> for an owned type
  • Vous ne pouvez pas appeler Entity<T>() avec un type détenu sur ModelBuilderYou cannot call Entity<T>() with an owned type on ModelBuilder

Défauts actuelsCurrent shortcomings

  • Hiérarchies d’héritage qui incluent détenus types d’entité ne sont pas pris en charge.Inheritance hierarchies that include owned entity types are not supported
  • Les navigations de référence pour détenus types d’entité ne peut pas être null, sauf si elles sont explicitement mappées à une table distincte du propriétaireReference navigations to owned entity types cannot be null unless they are explicitly mapped to a separate table from the owner
  • Instances de types d’entité détenus ne peut pas être partagées par plusieurs propriétaires (il s’agit d’un scénario bien connu pour les objets de valeur qui ne peut pas être implémenté à l’aide des types d’entité détenus)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)

Lacunes dans les versions précédentesShortcomings in previous versions

  • Dans EF Core 2.0, navigations à la propriété types d’entité ne peut pas être déclarés dans les types d’entité dérivés, sauf si les entités sont explicitement mappées à une table distincte de la hiérarchie de propriétaire.In EF Core 2.0, navigations to owned entity types cannot be declared in derived entity types unless the owned entities are explicitly mapped to a separate table from the owner hierarchy. Cette limitation a été supprimée dans EF Core 2.1This limitation has been removed in EF Core 2.1
  • En EF Core 2.0 et 2.1 uniquement référence aux navigations vers les types détenus ont été pris en charge.En EF Core 2.0 and 2.1 only reference navigations to owned types were supported. Cette limitation a été supprimée dans EF Core 2.2This limitation has been removed in EF Core 2.2