Campos de Backup

Os campos de suporte permitem que o EF leia e/ou grave em um campo em vez de em uma propriedade. Isso pode ser útil quando o encapsulamento na classe está sendo usado para restringir o uso e/ou aprimorar a semântica em torno do acesso aos dados pelo código do aplicativo, mas o valor deve ser lido e/ou gravado no banco de dados sem usar essas restrições/aprimoramentos.

Configuração básica

Por convenção, os seguintes campos serão descobertos como campos de suporte para uma determinada propriedade (listados em ordem de precedência).

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

No exemplo a seguir, a propriedade Url é configurada para ter _url como campo de suporte:

public class Blog
{
    private string _url;

    public int BlogId { get; set; }

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

Observe que os campos de suporte só são descobertos para propriedades incluídas no modelo. Para obter mais informações sobre quais propriedades estão incluídas no modelo, consulte Como Incluir e Excluir Propriedades.

Você também pode configurar campos de suporte usando as Anotações de Dados ou a API Fluente, por exemplo, se o nome do campo não corresponder às convenções acima:

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

Acesso ao campo e à propriedade

Por padrão, o EF sempre lerá e gravará no campo de suporte, supondo que ele tenha sido configurado corretamente, e nunca usará a propriedade. No entanto, o EF também dá suporte a outros padrões de acesso. Por exemplo, o exemplo a seguir instrui o EF a gravar no campo de suporte somente durante a materialização e a usar a propriedade em todos os outros casos:

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

Confira o enum PropertyAccessMode para obter o conjunto completo de opções com suporte.

Propriedades somente de campo

Você também pode criar uma propriedade conceitual em seu modelo que não tem uma propriedade CLR correspondente na classe de entidade, mas que, em vez disso, usa um campo para armazenar os dados na entidade. Isso é diferente de Propriedades de Sombra, em que os dados são armazenados no rastreador de alterações, e não no tipo de CLR da entidade. As propriedades somente de campo são comumente usadas quando a classe de entidade usa métodos em vez de propriedades para obter/definir valores, ou nos casos em que os campos não devem ser expostos de forma alguma no modelo de domínio (por exemplo, chaves primárias).

Você pode configurar uma propriedade somente de campo fornecendo um nome na API Property(...):

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

O EF tentará encontrar uma propriedade CLR com o nome fornecido ou um campo se a propriedade não for encontrada. Se nem uma propriedade nem um campo forem encontrados, uma propriedade de sombra será configurada em seu lugar.

Talvez seja necessário fazer referência a uma propriedade somente de campo a partir de consultas LINQ, mas esses campos geralmente são privados. Você pode usar o método EF.Property(...) em uma consulta LINQ para fazer referência ao campo:

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