支援欄位Backing Fields

注意

這項功能是在 EF Core 1.1 的新功能。This feature is new in EF Core 1.1.

支援欄位可讓 EF 來讀取和/或寫入的欄位,而不是屬性。Backing fields allow EF to read and/or write to a field rather than a property. 這有助於進行應用程式程式碼封裝在類別中的用來限制的使用和/或增強對資料的存取語意,但值應該是從讀取和/或寫入資料庫,而不需使用這些限制 /增強功能。This can be useful when encapsulation in the class is being used to restrict the use of and/or enhance the semantics around access to the data by application code, but the value should be read from and/or written to the database without using those restrictions/enhancements.

慣例Conventions

依照慣例,您會探索下列欄位,為支援給定的屬性 (依照優先順序列出) 的欄位。By convention, the following fields will be discovered as backing fields for a given property (listed in precedence order). 欄位只會探索模型中包含的屬性。Fields are only discovered for properties that are included in the model. 屬性包含在模型的詳細資訊,請參閱包含與排除屬性For more information on which properties are included in the model, see Including & Excluding Properties.

  • _<camel-cased property name>
  • _<property name>
  • m_<camel-cased property name>
  • m_<property name>
public class Blog
{
    private string _url;

    public int BlogId { get; set; }

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

設定支援欄位時,EF 會直接寫入該欄位時具體化實體執行個體,從資料庫 (而不使用屬性 setter)。When a backing field is configured, EF will write directly to that field when materializing entity instances from the database (rather than using the property setter). 如果 EF 需要讀取或寫入值,在其他時候,它會盡可能使用屬性。If EF needs to read or write the value at other times, it will use the property if possible. 比方說,如果 EF 必須更新屬性的值,它會使用屬性 setter,如果有定義。For example, if EF needs to update the value for a property, it will use the property setter if one is defined. 如果屬性是唯讀,則會寫入至欄位。If the property is read-only, then it will write to the field.

資料註釋Data Annotations

無法設定支援欄位,使用資料註解。Backing fields cannot be configured with data annotations.

Fluent APIFluent API

您可以使用 Fluent API 來設定屬性的支援欄位。You can use the Fluent API to configure a backing field for a property.

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

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

public class Blog
{
    private string _validatedUrl;

    public int BlogId { get; set; }

    public string Url
    {
        get { return _validatedUrl; }
    }

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

        _validatedUrl = url;
    }
}

控制欄位的使用時機Controlling when the field is used

您可以設定當 EF 所使用的欄位或屬性。You can configure when EF uses the field or property. 請參閱PropertyAccessMode 列舉解支援的選項。See the PropertyAccessMode enum for the supported options.

modelBuilder.Entity<Blog>()
    .Property(b => b.Url)
    .HasField("_validatedUrl")
    .UsePropertyAccessMode(PropertyAccessMode.Field);

不含屬性的欄位Fields without a property

您也可以在模型中的實體類別,沒有對應的 CLR 屬性,但改為使用欄位,來將資料儲存在實體中建立的概念的屬性。You can also create a conceptual property in your model that does not have a corresponding CLR property in the entity class, but instead uses a field to store the data in the entity. 這點不同於遮蔽屬性、 變更追蹤程式中儲存資料。This is different from Shadow Properties, where the data is stored in the change tracker. 此外,這通常會用如果實體類別會使用方法來取得或設定值。This would typically be used if the entity class uses methods to get/set values.

您可以提供 EF 中的欄位名稱Property(...)API。You can give EF the name of the field in the Property(...) API. 如果沒有具有指定名稱的屬性,然後 EF 會尋找欄位。If there is no property with the given name, then EF will look for a field.

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

您也可以選擇為屬性提供的名稱,而不是欄位名稱。You can also choose to give the property a name, other than the field name. 建立模型時,則會使用此名稱,最值得注意的是它會使用對應至資料庫中的資料行名稱。This name is then used when creating the model, most notably it will be used for the column name that is mapped to in the database.

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

當這個實體類別中沒有任何屬性時,您可以使用EF.Property(...)方法在 LINQ 查詢中參考的概念模型的一部分的屬性。When there is no property in the entity class, you can use the EF.Property(...) method in a LINQ query to refer to the property that is conceptually part of the model.

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