使用来自 Postgres jsonb 列的顶级字典映射到 POCO

Mapping to POCOs with top-level dictionary from Postgres jsonb column

我有一个使用 EF Core 和 Postgres 数据库的 .NET Core 3.1 应用程序。在数据库中,我有一个 jsonb 列,我现在想将其映射到 EF Core 中定义明确的一组 类。

jsonb 列的内容如下所示:

{
    "entry1": {
        "name": "entry1",
        "contents": {
            "entry1.1": {
                "name": "entry1.1"
            },
            "entry1.2": {
                "name": "entry1.2",
                "contents": {
                    "entry1.2.1": {
                        "name": "entry1.2.1"
                    }
                }
            }
        }
    }
}

在顶层,它是一个将字符串映射到条目的字典。每个条目都有一个名称并且可以有内容,这又是一个将字符串映射到条目的字典。

public class Entry
{
    public string name { get; set; }
    public Dictionary<string, Entry> contents { get; set; }
}

jsonb 列本身是在 table 上定义的,如下所示:

public class MyTable {
    [Column(TypeName = "jsonb")]
    public Dictionary<string, Entry> Entries { get; set; }
}

现在的问题是它根本不起作用。当我使用 EF Core 从数据库中获取条目时,"Entries" 属性 确实包含一个带有单个键 "entry1" 的字典,但该键的值为空 Entry 对象(名称和内容均为空)。

Npgsql documentation on mapping jsonb columns to POCOs 没有解释在这种情况下如何处理字典。我在 jsonb 列中找不到任何带有顶级字典的示例,所以我不完全确定我这样做是对的。

我怎样才能正确连接它以便我的 jsonb 列映射到 Entry 对象的字典?

以下似乎效果不错:

class Program
{
    static void Main(string[] args)
    {
        using (var createCtx = new BlogContext())
        {
            createCtx.Database.EnsureDeleted();
            createCtx.Database.EnsureCreated();

            createCtx.Blogs.Add(new Blog
            {
                Entries = new Dictionary<string, Entry>
                {
                    { "bla", new Entry { Foo = "foo1" }}
                }
            });

            createCtx.SaveChanges();
        }

        using var ctx = new BlogContext();

        var results = ctx.Blogs.Single();
        Console.WriteLine(results.Entries["bla"].Foo);
    }
}

public class BlogContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

    static ILoggerFactory ContextLoggerFactory
        => LoggerFactory.Create(b => b.AddConsole().AddFilter("", LogLevel.Information));

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
            .UseNpgsql(@"Host=localhost;Database=test;Username=npgsql_tests;Password=npgsql_tests")
            .EnableSensitiveDataLogging()
            .UseLoggerFactory(ContextLoggerFactory);
}

public class Blog
{
    public int Id { get; set; }
    [Column(TypeName = "jsonb")]
    public Dictionary<string, Entry> Entries { get; set; }
}

public class Entry
{
    public string Foo { get; set; }
}

在数据库中:

test=# select * from "Blogs"
test-# ;
 Id | Name |         Entries          
----+------+--------------------------
  1 |      | {"bla": {"Foo": "foo1"}}
(1 row)