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

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

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

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

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

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

Резервные поля также можно настроить с помощью аннотации данных (доступно в Ефкоре 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);
}

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

Примечание

В EF Core 3,0 режим доступа к свойству по умолчанию изменен с PreferFieldDuringConstruction на PreferField .

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

Можно также создать концептуальное свойство в модели, которое не имеет соответствующего свойства 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"));