Отображение в POCO с помощью словаря верхнего уровня из столбца Postgres jsonb - PullRequest
0 голосов
/ 30 апреля 2020

У меня есть приложение. NET Core 3.1, использующее EF Core и базу данных Postgres. В базе данных у меня есть один столбец 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 определен в таблице следующим образом:

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

Проблема с этим сейчас в том, что это просто не работает. Когда я выбираю запись из базы данных с помощью EF Core, свойство «Entries» действительно содержит словарь с одним ключом «entry1», но значение этого ключа - пустой объект Entry (имя и содержимое имеют нулевое значение ).

Документация Npg sql по отображению столбцов jsonb в POCO не объясняет, как обрабатывать словари в этом случае. Я не смог найти ни одного примера со словарем верхнего уровня в столбце jsonb, поэтому я не совсем уверен, что все делаю правильно.

Как мне правильно подключить это, чтобы мой столбец jsonb отображается в словарь объектов Entry?

1 Ответ

1 голос
/ 04 мая 2020

Кажется, хорошо работает следующее:

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)
...