实体框架:在场景后面序列化/反序列化JSON列

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实体框架:在场景后面序列化/反序列化JSON列相关的知识,希望对你有一定的参考价值。

我有Code First类/表,其中一个字段有string / nvarchar类型。此字符串是MyClass实例的JSON表示形式。我想在仅使用MyClass实例的代码中操作,但是将其作为字符串(JSON)存储在数据库中。假设我的表看起来像这样:

public class Message
{
    [Key]
    public int Id { get; set; }
    public string Title { get; set; }
    public string JsonDefinition { get; set; }
}

我更喜欢这样

public class Message
{
    [Key]
    public int Id { get; set; }
    public string Title { get; set; }
    [JSON]
    public MyClass JsonDefinition { get; set; }
}

其中JSON是一个自定义属性,它告诉EF将字段存储为MyClass实例的序列化字符串。同时它说EF:“一旦你拉动实体,用反序列化的MyClass实例替换JsonDefinition字符串”

现有的EF 4机制是否可以实现?如果是这样,那怎么样?

提前致谢。

编辑:MyClass可以是字典或任何其他复杂类型。

答案

不是直接的。您必须始终在类中包含字符串属性,因为EF要求它具有持久性。您还可以使用非映射的MyClass属性,但必须手动处理序列化和反序列化并使这些属性同步。

天真的解决方案是在MyClass中实现INotifyPropertyChanged,并确保MyClass值或其任何属性中的每个更改都将触发JSON序列化到字符串属性。这种天真的解决方案适用于一些简单的问题,但在这种情况下,这是一个非常糟糕的主意,因为如果您在指定的MyClass属性上修改了很多属性,它会产生很大的性能影响。

另一种方法是使用EF的钩子进行物化并保存更改。你需要处理ObjectContext.ObjectMaterialized事件(你可以通过ObjectContext明确实施的DbContextIObjectContextAdapter获得DbContext)。在此事件处理程序中,您将使用字符串属性的值并将其内容反序列化为MyClass属性。您还必须覆盖DbContext.SaveChanges,您将在其中查找应插入或更新的所有Message实例,并使用其MyClass属性获取当前值并将其序列化为字符串属性。

您正在寻找的是一些复杂的映射方案或映射转换。 EF不支持他们,但你可以投票给我对Data UserVoice的建议。

另一答案

我会尝试如下:

public class Message
{
    [Key]
    public int Id { get; set; }
    public string Title { get; set; }

    [Column(TypeName = "jsonb")]
    [JsonIgnore]
    public string JMyClass { get; set; }

    [NotMapped]
    public MyClass JsonDefinition 
    {
        get => JsonConvert.DeserializeObject<MyClass>(JMyClass );
        set => JMyClass = JsonConvert.SerializeObject(value);
    }
}

以上是关于实体框架:在场景后面序列化/反序列化JSON列的主要内容,如果未能解决你的问题,请参考以下文章

将 Json 反序列化为实体框架无法将 int 转换为类型

C#动态实体集的反序列化(动态JSON反序列化)

SpringMVC Json自定义序列化和反序列化

Symfony 序列化器:将 Json 反序列化为实体

反序列化多层嵌套json实体

通过 Web 传输实体框架对象并通过 JSON 返回的最佳方式