使用来自 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)
我有一个使用 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)