Свойства теневой копии и индексатора

Теневые свойства — это свойства, не определенные в классе сущности .NET, но определенные для этого типа сущности в модели EF Core. Значения и состояния этих свойств хранятся исключительно в средстве отслеживания изменений. Теневые свойства полезны при наличии в базе данных данных, которые не должны быть представлены в сопоставленных типах сущностей.

Свойства индексатора — это свойства типа сущности, которые поддерживаются индексатором в классе сущности .NET. Доступ к ним можно получить с помощью индексатора в экземплярах класса .NET. Он также позволяет добавлять дополнительные свойства в тип сущности, не изменяя класс CLR.

Свойства тени внешнего ключа

Свойства теневой копии чаще всего используются для свойств внешнего ключа, где связь между двумя сущностями представляется значением внешнего ключа в базе данных, но Управление связью осуществляется на основе типов сущностей с помощью свойств навигации между типами сущностей. По соглашению EF будет представлять теневое свойство при обнаружении связи, но свойство внешнего ключа не найдено в зависимом классе сущности.

Свойству будет присвоено имя <navigation property name><principal key property name> (Навигация по зависимой сущности, которая указывает на основную сущность, используется для именования). Если имя свойства ключа участника включает имя свойства навигации, то имя будет иметь значение <principal key property name> . Если в зависимой сущности нет свойства навигации, в его месте используется имя типа участника.

Например, приведенный ниже листинг кода приведет к тому, что в BlogId сущность будет введено свойство Shadow 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; }
}

Настройка теневых свойств

для настройки теневых свойств можно использовать API Fluent. После вызова перегрузки строки Property можно связать любой из вызовов конфигурации для других свойств. В следующем примере, поскольку не Blog имеет свойства CLR с именем LastUpdated , создается свойство Shadow:

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; }
}

Если имя, передаваемое в Property метод, совпадает с именем существующего свойства (теневого или определенного для класса сущностей), то код настроит это существующее свойство, а не создаст новое свойство Shadow.

Доступ к теневым свойствам

Значения теневых свойств можно получить и изменить с помощью ChangeTracker API:

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

На теневые свойства можно ссылаться в запросах LINQ с помощью EF.Property статического метода:

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

Доступ к теневым свойствам после неотслеживаемого запроса невозможен, так как отслеживание изменений не отслеживает возвращаемые сущности.

Настройка свойств индексатора

для настройки свойств индексатора можно использовать API Fluent. После вызова метода IndexerProperty можно связать любой из вызовов конфигурации для других свойств. В следующем примере Blog определен индексатор, который будет использоваться для создания свойства индексатора.

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;
    }
}

Если имя, передаваемое в IndexerProperty метод, совпадает с именем существующего свойства индексатора, то код настроит это существующее свойство. Если тип сущности имеет свойство, которое поддерживается свойством класса сущностей, возникает исключение, так как свойства индексатора должны быть доступны только через индексатор.

На свойства индексатора можно ссылаться в запросах LINQ с помощью EF.Property статического метода, как показано выше, или с помощью свойства индексатора среды CLR.

Типы сущностей контейнера свойств

Примечание

Поддержка типов сущностей контейнера свойств была представлена в EF Core 5,0.

Типы сущностей, которые содержат только свойства индексатора, называются типами сущностей контейнера свойств. Эти типы сущностей не имеют теневых свойств, а EF создает свойства индексатора. Сейчас Dictionary<string, object> поддерживается только в качестве типа сущности контейнера свойств. Он должен быть настроен в качестве типа сущности общего типа с уникальным именем, а соответствующее свойство должно быть реализовано с помощью Set вызова.

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");
            });
    }
}

Типы сущностей контейнера свойств можно использовать везде, где используется стандартный тип сущности, в том числе в качестве типа принадлежащей сущности. Однако у них есть определенные ограничения.