【问题标题】:How to convert a class instance to JsonDocument?如何将类实例转换为 JsonDocument?
【发布时间】:2020-07-14 07:32:04
【问题描述】:

假设我们有一个如下所示的实体类:

public class SerializedEntity
{
    public JsonDocument Payload { get; set; }

    public SerializedEntity(JsonDocument payload)
    {
        Payload = payload;
    }
}

根据npsql,这将为此类生成一个列payload 类型为jsonb 的表,这是正确的。

现在我想做的是获取 any 类实例并将其作为payload 存储在此表中,例如:

public class Pizza {
    public string Name { get; set; }
    public int Size { get; set; }
}

然后应该可以作为具有以下结构的对象进行检索:

{Name: "name", Size: 10}

所以我需要这样的东西:

var pizza = new Pizza("Margharita", 10);
var se = new SerializedEntity(someConverter.method(pizza))

【问题讨论】:

标签: c# entity-framework asp.net-core npgsql


【解决方案1】:

System.Text.Json 有点尴尬但可能:

using System.Text.Json;
using System.Text.Json.Serialization;

var pizza = new Pizza("Margharita", 10);
var se = new SerializedEntity(JsonDocument.Parse(JsonSerializer.Serialize(pizza)));

自(我认为)v3.0 以来,它已内置于 dotnet core,因此您不需要任何额外的 3rd 方库。只是不要忘记usings。

不过,可能有一些技巧可以让解析效率更高一些(使用异步 API,或者像 Magnus 建议的那样,使用 SerializeToUtf8Bytes 序列化为二进制文件)。

我找不到任何直接从TobjectJsonDocument 的方法。我不敢相信这是不是以某种方式可能。如果您知道这是如何工作的,请发表评论或添加您的答案。

【讨论】:

  • JsonSerializer.Serialize 的输出是一个字符串,而我的构造函数采用 JsonDocument。我可以将一个对象转换为字符串,然后使用 JsonDocument.Parse 创建一个 JsonDocument,但由于我想稍后将其保存到数据库中,我想它会再次被序列化。
  • 已编辑以反映您使用 JsonDocument @pbn 的需要
  • 请注意 JsonDocument 是一次性的。 docs.microsoft.com/en-us/dotnet/api/…
【解决方案2】:

对其进行序列化,然后将其解析为 JsonDocument。

var doc = JsonDocument.Parse(JsonSerializer.SerializeToUtf8Bytes(
                new Pizza {Name = "Calzone", Size = 10}));

【讨论】:

  • 那么,真的没有办法围绕序列化/解析?
  • @Fildor 似乎是thinking about it,但现在放弃了这个想法。
【解决方案3】:

如果您的 EF 实体 (SerializedEntity) 将始终将 Pizza 作为其序列化 JSON 文档,那么您可以简单地使用 POCO mapping - 将 JsonDocument 属性替换为 Pizza 属性,并将其映射到 jsonb 列。

如果您想要的实际类型不同(有时是 Pizza,有时是其他类型),您还可以将 object 属性映射到 jsonb,然后分配您想要的任何内容。 Npgsql 会在内部将任何对象序列化为 JSON:

class Program
{
    static void Main()
    {
        using var ctx = new BlogContext();
        ctx.Database.EnsureDeleted();
        ctx.Database.EnsureCreated();

        ctx.FoodEntities.Add(new FoodEntity { SomeJsonFood = new Pizza { Name = "Napoletana" } });
        ctx.FoodEntities.Add(new FoodEntity { SomeJsonFood = new Sushi { FishType = "Salmon" } });
        ctx.SaveChanges();
    }
}

public class BlogContext : DbContext
{
    public DbSet<FoodEntity> FoodEntities { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder.UseNpgsql("...");
}

public class FoodEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
    [Column(TypeName = "jsonb")]
    public object SomeJsonFood { get; set; }
}

public class Pizza
{
    public string Name { get; set; }
    public int Size { get; set; }
}

public class Sushi
{
    public string FishType { get; set; }
}

【讨论】:

【解决方案4】:

我的最终解决方案:

public class SerializedEntity
{
    public object? Payload { get; set; }

    public SerializedEntity(object? payload)
    {
        Payload = payload;
    }
}

以及它的 EF 配置:

public void Configure(EntityTypeBuilder<SerializedEntity> builder)
{
    builder.Property(n => n.Payload).HasColumnType("jsonb").HasConversion(
        v => JsonConvert.SerializeObject(v,
            new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore}),
        v => JsonConvert.DeserializeObject<object?>(v,
            new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore}));
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-29
    • 2010-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-27
    • 1970-01-01
    • 2023-04-10
    相关资源
    最近更新 更多