簡體   English   中英

EF Core 支持字段 - 將屬性公開為另一種類型?

[英]EF Core Backing fields - expose property as another type?

假設我有一個 EF 實體類 Person,上面有一個 PhoneNumber。 PhoneNumber 存儲為字符串類型,但我希望 Person 上的所有訪問都通過 Phone ,它具有一些不錯的訪問器功能,例如驗證或GetAreaCode() 我想將它作為字符串返回到數據庫中,但是在查詢時我想將它作為 PhoneNumber 返回:

public class Person {
    public PhoneNumber Phone { /* Some clever get/set logic here */ }

    private string _phoneNumber; // Backing field
}

或者我可以讓 PhoneNumber 將自己存儲為字符串? 如果我只是通過刪除上面的支持字段將它包含在模型中,EF 就會被構造函數(一個受保護的構造函數,其參數比一個字符串多一些)和復制構造函數PhoneNumber(PhoneNumber other)混淆。 我可以讓 EF 以某種方式忽略那些嗎?

我對想法持開放態度...

您可以使用@nbrosz 的答案來解決您的問題,但如果您使用的是 EF Core 2.1,則不再需要執行此類解決方法。 您可以通過使用 EF Core 2.1(自 2018 年 5 月 7 日起在Release Candidate 1 中)擺脫支持字段,您可以使用 Microsoft 在此處解釋的價值轉換功能:

值轉換器允許在讀取或寫入數據庫時​​轉換屬性值。 這種轉換可以是從一個值到另一個相同類型的值(例如,加密字符串)或從一種類型的值到另一種類型的值(例如,將枚舉值與數據庫中的字符串相互轉換。)

因此,對於您的情況,您可以刪除支持字段。 你不再需要它。 你的類應該是這樣的:

public class Person 
{
    public PhoneNumber Phone { /* Some clever get/set logic here */ }
}

在您的OnModelCreating方法中,您可以像下面這樣配置轉換:

modelBuilder.Entity<Person>()
    .Property(p => p.Phone)
    .HasConversion(
        phone => { 
            // Here you code the logic of how to get the value to store in DB
            return ...;
        },
        dbValue => { 
            // Here you code the logic of how to construct the PhoneNumber instance from the value to store in DB
        }
    );

就是這樣。 實際上它在候選版本中,但微軟說:

EF Core 2.1 RC1 是一個“上線”版本,這意味着一旦您測試您的應用程序與 RC1 一起正常工作,您就可以在生產中使用它並獲得 Microsoft 的支持,但是一旦可用,您仍應更新到最終穩定版本.

我的其余答案是針對@nbrosz 的,因為您正在處理枚舉類型。 您可以刪除支持字段,也可以刪除 EF Core 2.1 提供的許多內置值轉換器之一。 對於枚舉到字符串值的轉換,我們有EnumToStringConverter類型。 對於您在答案中所做的邏輯,您可以將其簡化為實體:

[Display(Name = "Fire Type")]
public Enums.FireType Type { get; set; }

我們刪除了屬性上的NotMapped屬性,並且沒有用於轉換的邏輯 y。

在您的OnModelCreating方法中,您可以這樣做:

var converter = new EnumToStringConverter<FireType>();

modelBuilder
    .Entity<Fire>()
    .Property(e => e.FireType)
    .HasConversion(converter);

您還可以使用HasConversion<T>的通用版本,讓 EF Core 為您檢測正確的轉換器,如下所示:

modelBuilder
    .Entity<Fire>()
    .Property(e => e.FireType)
    .HasConversion<string>();

如果您不喜歡使用流暢的配置,您可以使用如下所示的Column數據注釋屬性,EF Core 將為您進行轉換:

[Column(TypeName = "nvarchar(20)")]
[Display(Name = "Fire Type")]
public Enums.FireType Type { get; set; }

我發現在 EF Core 2.0 中有效的唯一方法是創建一個帶有 getter/setter 的公共屬性,其名稱與您的支持字段不匹配,並將其標記為 NotMapped,如下所示:

    [NotMapped]
    [Display(Name = "Fire Type")]
    public Enums.FireType Type
    {
        get
        {
            Enums.FireType type;
            if (!Enum.TryParse(_fireType, out type))
                type = Enums.FireType.Fire; // default

            return type;
        }
        set
        {
            _fireType = value.ToString();
        }
    }
    
    private string _fireType;

然后在您的 DbContext 的 OnModelCreating 方法中,告訴它在數據庫表上創建一個列,其作用類似於支持屬性:

        // backing properties
        modelBuilder.Entity<Fire>()
            .Property<string>("FireType")
            .HasField("_fireType")
            .UsePropertyAccessMode(PropertyAccessMode.Field);

有了這個,我終於能夠創建一個成功的遷移,它允許我在我的模型上有一個私有字段,在模型上有一個公共轉換屬性,以及我的數據庫表中一個正確命名的列。 唯一的問題是公共屬性和私有字段不能共享相同的名稱(不共享相同的類型),但無論如何都不會是這種情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM