支援欄位Backing Fields

注意

這項功能是在 EF 核心 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. 這有助於進行應用程式碼,在類別中的封裝 (encapsulation) 用來限制的使用及/或加強周圍資料的存取權的語意,但值應該進行讀取及/或寫入資料庫,而不使用這些限制 /增強功能。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 應用程式開發介面Fluent API

您可以使用 fluent 應用程式開發的應用程式開發介面來設定屬性的支援欄位。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(...)應用程式開發介面。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"));