Вспомогательные поля

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

Базовая конфигурация

По условию, следующие поля будут обнаружены как резервные поля для заданного свойства (указанных в порядке приоритета).

  • <camel-cased property name>
  • _<camel-cased property name>
  • _<property name>
  • m_<camel-cased property name>
  • m_<property name>

В следующем примере свойство Url настроено так, чтобы использовать _url в качестве скрытого поля.

public class Blog
{
    private string _url;

    public int BlogId { get; set; }

    public string Url
    {
        get { return _url; }
        set { _url = value; }
    }
}

Обратите внимание, что резервные поля обнаруживаются только для свойств, включенных в модель. Дополнительные сведения о том, какие свойства включены в модель, см. в разделе "Включение и исключение свойств".

Вы также можете настроить резервные поля с помощью заметок данных или API Fluent, например, если имя поля не соответствует приведенным выше соглашениям:

public class Blog
{
    private string _validatedUrl;

    public int BlogId { get; set; }

    [BackingField(nameof(_validatedUrl))]
    public string Url
    {
        get { return _validatedUrl; }
    }

    public void SetUrl(string url)
    {
        // put your validation code here

        _validatedUrl = url;
    }
}

Доступ к полям и свойствам

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

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Property(b => b.Url)
        .HasField("_validatedUrl")
        .UsePropertyAccessMode(PropertyAccessMode.PreferFieldDuringConstruction);
}

Полный набор поддерживаемых параметров см. в перечислении PropertyAccessMode.

Свойства только для полей

Вы также можете создать концептуальное свойство в модели, которое не имеет соответствующего свойства CLR в классе сущностей, но вместо этого использует поле для хранения данных в сущности. Это отличается от Скрытых Свойств, где данные хранятся в трекере изменений, а не в CLR типе сущности. Свойства, доступные только для полей, обычно используются, если класс сущности использует методы вместо свойств для получения и задания значений, или в случаях, когда поля не должны предоставляться вообще в модели домена (например, первичные ключи).

Вы можете настроить свойство только для полей, указав имя в Property(...) API:

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

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

public class Blog
{
    private string _validatedUrl;

    public int BlogId { get; set; }

    public string GetUrl()
    {
        return _validatedUrl;
    }

    public void SetUrl(string url)
    {
        using (var client = new HttpClient())
        {
            var response = client.GetAsync(url).Result;
            response.EnsureSuccessStatusCode();
        }

        _validatedUrl = url;
    }
}

EF попытается найти свойство CLR с заданным именем или поле, если свойство не найдено. Если ни свойство, ни поле не найдены, вместо этого будет настроено теневое свойство.

Возможно, потребуется ссылаться на свойство, доступное только для полей в запросах LINQ, но такие поля обычно являются приватными. Метод можно использовать в запросе EF.Property(...) LINQ для ссылки на поле:

var blogs = db.blogs.OrderBy(b => EF.Property<string>(b, "_validatedUrl"));