Резервные поля

Резервные поля позволяют 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; }
    }
}

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

Вы также можете настроить резервные поля с помощью заметки к данным (доступной в EFCore 5.0) или 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"));