如何使用EF Core在實體字段中存儲JSON?

entity-framework-core json.net

我正在使用.NET Core創建一個可重用的庫(針對.NETStandard 1.4),我正在使用Entity Framework Core(兩者都是新的)。我有一個實體類,看起來像:

public class Campaign
{
    [Key]
    public Guid Id { get; set; }

    [Required]
    [MaxLength(50)]
    public string Name { get; set; }

    public JObject ExtendedData { get; set; }
}

我有一個定義DbSet的DbContext類:

public DbSet<Campaign> Campaigns { get; set; }

(我也在使用DI的Repository模式,但我不認為這是相關的。)

我的單元測試給了我這個錯誤:

System.InvalidOperationException:無法確定類型為“JContainer”的導航屬性“JToken.Parent”表示的關係。手動配置關係,或從模型中忽略此屬性。

有沒有辦法表明這不是一個關係,但應該存儲為一個大字符串?

一般承認的答案

@Michael的回答讓我走上正軌,但我的實施方式略有不同。我最終將值存儲為私有屬性中的字符串,並將其用作“後備字段”。然後,ExtendedData屬性將JObject轉換為set上的字符串,反之亦然:

public class Campaign
{
    // https://docs.microsoft.com/en-us/ef/core/modeling/backing-field
    private string _extendedData;

    [Key]
    public Guid Id { get; set; }

    [Required]
    [MaxLength(50)]
    public string Name { get; set; }

    [NotMapped]
    public JObject ExtendedData
    {
        get
        {
            return JsonConvert.DeserializeObject<JObject>(string.IsNullOrEmpty(_extendedData) ? "{}" : _extendedData);
        }
        set
        {
            _extendedData = value.ToString();
        }
    }
}

要將_extendedData設置為支持字段,我將其添加到我的上下文中:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Campaign>()
        .Property<string>("ExtendedDataStr")
        .HasField("_extendedData");
}

更新:Darren使用EF Core Value Conversions(EF Core 2.1的新功能 - 在此答案時尚不存在)的答案似乎是目前最好的方法。


熱門答案

要以不同的方式回答這個問題。

理想情況下,域模型應該不知道數據是如何存儲的。添加支持字段和額外的[NotMapped]屬性實際上將您的域模型與您的基礎架構耦合。

請記住 - 您的域名是王道,而不是數據庫。該數據庫僅用於存儲您域的部分內容。

相反,您可以在EntityTypeBuilder對像上使用EF Core的HasConversion()方法在您的類型和JSON之間進行轉換。

鑑於這兩個域模型:

public class Person
{
    public int Id { get; set; }

    [Required]
    [MaxLength(50)]
    public string FirstName { get; set; }

    [Required]
    [MaxLength(50)]
    public string LastName { get; set; }

    [Required]
    public DateTime DateOfBirth { get; set; }

    public IList<Address> Addresses { get; set; }      
}

public class Address
{
    public string Type { get; set; }
    public string Company { get; set; }
    public string Number { get; set; }
    public string Street { get; set; }
    public string City { get; set; }
}

我只添加了域感興趣的屬性 - 而不是數據庫感興趣的細節; IE沒有[Key]

我的IEntityTypeConfigurationPerson提供了以下IEntityTypeConfiguration

public class PersonsConfiguration : IEntityTypeConfiguration<Person>
{
    public void Configure(EntityTypeBuilder<Person> builder)
    {
        // This Converter will perform the conversion to and from Json to the desired type
        builder.Property(e => e.Addresses).HasConversion(
            v => JsonConvert.SerializeObject(v, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }),
            v => JsonConvert.DeserializeObject<IList<Address>>(v, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }));
    }
}

使用此方法,您可以完全將域與基礎架構分離。無需所有支持字段和額外屬性。



Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow