Partage via


Propriétés de l’ombre et de l’indexeur

Les propriétés d’ombre sont des propriétés qui ne sont pas définies dans votre classe d’entité .NET, mais qui sont définies pour ce type d’entité dans le modèle EF Core. La valeur et l’état de ces propriétés sont conservés uniquement dans le Change Tracker. Les propriétés d’ombre sont utiles lorsqu’il existe des données dans la base de données qui ne doivent pas être exposées sur les types d’entités mappés.

Les propriétés de l’indexeur sont des propriétés de type d’entité, qui sont sauvegardées par un indexeur dans la classe d’entité .NET. Ils sont accessibles à l’aide de l’indexeur sur les instances de classe .NET. Il vous permet également d’ajouter des propriétés supplémentaires au type d’entité sans modifier la classe CLR.

Propriétés de l’ombre de clé étrangère

Les propriétés d’ombre sont souvent utilisées pour les propriétés de clé étrangère, où elles sont ajoutées au modèle par convention lorsqu’aucune propriété de clé étrangère n’a été trouvée par convention ou configurée explicitement. La relation est représentée par les propriétés de navigation, mais dans la base de données, elle est appliquée par une contrainte de clé étrangère et la valeur de la colonne de clé étrangère est stockée dans la propriété d’ombre correspondante.

La propriété sera nommée <navigation property name><principal key property name> (la navigation sur l’entité dépendante, qui pointe vers l’entité principale, est utilisée pour le nommage). Si le nom de la propriété de clé principale commence par le nom de la propriété de navigation, le nom sera simplement <principal key property name>. S’il n’existe aucune propriété de navigation sur l’entité dépendante, le nom de type principal concaténé avec le nom de propriété de clé primaire ou alternative est utilisé à sa place <principal type name><principal key property name>.

Par exemple, la liste de codes suivante entraîne l’introduction d’une BlogId propriété d’ombre à l’entité Post :

internal class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    // Since there is no CLR property which holds the foreign
    // key for this relationship, a shadow property is created.
    public Blog Blog { get; set; }
}

Configuration des propriétés d’ombre

Vous pouvez utiliser l’API Fluent pour configurer les propriétés d’ombre. Une fois que vous avez appelé la surcharge de chaîne de Property<TProperty>(String), vous pouvez chaîner n'importe quel appel de configuration que vous feriez pour d'autres propriétés. Dans l’exemple suivant, étant donné qu’aucune Blog propriété CLR n’est nommée LastUpdated, une propriété d’ombre est créée :

internal class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .Property<DateTime>("LastUpdated");
    }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
}

Si le nom fourni à la Property méthode correspond au nom d’une propriété existante (une propriété d’ombre ou une propriété définie sur la classe d’entité), le code configure cette propriété existante plutôt que d’introduire une nouvelle propriété d’ombre.

Accès aux propriétés d’ombre

Les valeurs de propriété Shadow peuvent être obtenues et modifiées via l’API ChangeTracker :

context.Entry(myBlog).Property("LastUpdated").CurrentValue = DateTime.Now;

Les propriétés d’ombre peuvent être référencées dans les requêtes LINQ via la EF.Property méthode statique :

var blogs = context.Blogs
    .OrderBy(b => EF.Property<DateTime>(b, "LastUpdated"));

Les propriétés d’ombre ne sont pas accessibles après une requête sans suivi, car les entités retournées ne sont pas suivies par le suivi des modifications.

Configuration des propriétés de l’indexeur

Vous pouvez utiliser l’API Fluent pour configurer les propriétés de l’indexeur. Une fois que vous avez appelé la méthode IndexerProperty, vous pouvez chaîner l’un des appels de configuration que vous feriez pour d’autres propriétés. Dans l’exemple suivant, Blog un indexeur est défini et il sera utilisé pour créer une propriété d’indexeur.

internal class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>().IndexerProperty<DateTime>("LastUpdated");
    }
}

public class Blog
{
    private readonly Dictionary<string, object> _data = new Dictionary<string, object>();
    public int BlogId { get; set; }

    public object this[string key]
    {
        get => _data[key];
        set => _data[key] = value;
    }
}

Si le nom fourni à la IndexerProperty méthode correspond au nom d’une propriété d’indexeur existante, le code configure cette propriété existante. Si le type d’entité a une propriété, qui est sauvegardée par une propriété sur la classe d’entité, une exception est levée, car les propriétés de l’indexeur doivent uniquement être accessibles via l’indexeur.

Les propriétés de l’indexeur peuvent être référencées dans les requêtes LINQ via la EF.Property méthode statique, comme indiqué ci-dessus ou à l’aide de la propriété d’indexeur CLR.

Types d’entités de Property Bag

Les types d’entités qui contiennent uniquement des propriétés d’indexeur sont appelés types d’entités de conteneur de propriétés. Ces types d’entités n’ont pas de propriétés d’ombre et EF crée des propriétés d’indexeur à la place. Actuellement, seul le type d'entité de sac de propriétés Dictionary<string, object> est pris en charge. Il doit être configuré en tant que type d’entité de type partagé avec un nom unique et la propriété correspondante DbSet doit être implémentée à l’aide d’un Set appel.

internal class MyContext : DbContext
{
    public DbSet<Dictionary<string, object>> Blogs => Set<Dictionary<string, object>>("Blog");

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.SharedTypeEntity<Dictionary<string, object>>(
            "Blog", bb =>
            {
                bb.Property<int>("BlogId");
                bb.Property<string>("Url");
                bb.Property<DateTime>("LastUpdated");
            });
    }
}

Les types d'entités de sac de propriétés peuvent être utilisés partout où un type d'entité normal est utilisé, y compris en tant que type d'entité propriétaire. Toutefois, ils ont certaines limitations :