Entity Framework Core jsonb列类型

37

我正在使用Entity Framework Core与npgsql postgresql来进行编程。

我的问题是,使用迁移操作,如何标记一个类属性以生成JSONB列类型?

例如:

public class MyTableClass
{
    public int Id { get; set; }

    // My JSONB column
    public string Data { get; set; }
}

提前感谢。


3
你尝试过使用Byte[],并在实体映射中将列类型设置为jsonb吗? - H. Herzl
你能使用EF Core查询jsonb吗?例如,查询JSON文档的属性。 - zaitsman
zaitsman,我认为目前这不可能。请看 https://github.com/aspnet/EntityFrameworkCore/issues/4021 。我有一个 SQL 查询。我正在使用以下内容来读取结果: https://github.com/aspnet/EntityFrameworkCore/issues/1862#issuecomment-331081468 。我已经发现了与 DateTimeOffset 和 DateTime 相关的代码问题。如果你遇到了这个问题,我可以向你展示我的解决方法。 - bruno.almeida
3个回答

50
根据赫尔茨尔的评论:
我的最终解决方案大致如下:
public class MyTableClass
{
    public int Id { get; set; }

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

迁移生成了这个:
Data = table.Column<string>(type: "jsonb", nullable: true),

当使用迁移更新数据库时,Data列以jsonb类型正确创建。

1
@Alex Klaus,很遗憾,这个链接已经失效了。 - wegry
3
@wegry,这是链接 - https://www.npgsql.org/efcore/mapping/general.html#explicitly-specifying-data-types - Alex Klaus
@Matt,这很奇怪。如果您删除了表格,那么列如何已经存在呢? - bruno.almeida
@bruno.almeida - 这是由于“迁移历史”造成的 - EF.Core Code First 保留了每一步操作,而我在之前的迁移步骤中将该列“my_column”设置为文本。所以我发现 EF Core 正试图将“text”转换为“jsonb”,但失败了。即使在 pgAdmin 中,如果您编辑表并想要更改列数据类型,也无法选择 jsonb。唯一有效的方法是创建一个新的类型为“jsonb”的列,并使用不同的名称,然后删除旧列。如果该列以前不存在,则您很幸运。也许可以通过放弃一些迁移步骤来解决问题。 - Matt
一些额外的细节请参考:https://www.npgsql.org/efcore/mapping/json.htm - Neil
显示剩余3条评论

25

使用 @bruno.almeida 建议的 string 是一个不错的解决方案,但是无法查询

其他的方法包括:

  • 使用 System.Text.Json DOM 类型(JsonDocument 或 JsonElement)
  • 使用强类型的用户定义类型(POCOs)

JsonDocument 是我最喜欢的,因为它可以进行查询,而且灵活快捷,例如:

public JsonDocument Customer { get; set; }

更多细节请参见:https://www.npgsql.org/efcore/mapping/json.html


1
关于可用选项的@链接,写得很好。 - bvj
1
这应该是被接受的答案。 - undefined

1
除了@bruno.almeida的回答之外,值得注意的是可以向JSONB列添加类型。例如,我最近创建了一个列来保存各种文件上传错误:
我有一个名为RecordErrors的类,我认为它足够通用,可以在许多错误存储情况下使用:
public class RecordErrors
{
    public IEnumerable<ResultError> Errors { get; set; } = Enumerable.Empty<ResultError>();
}

ResultError类只是具有额外属性,如ErrorCodeMessage,但如果您想要简单的字符串错误值,它可以很容易地被替换为String

我的实体看起来像这样:

public class MyFileUpload
{
    public int Id { get; set; }

    [StringLength(800)]
    public string Name { get; set; } = string.Empty;
    ...

    [Column(TypeName = "jsonb")]
    public RecordErrors? Errors { get; set; } = null;
}

运行迁移会创建一个带有jsonb类型的列。

然后,您可以使用通常的方式将数据保存到数据库中:

 _databaseContext.SaveChangesAsync(cancellationToken);

在我的实例中,数据库中的结果是类似于以下 JSON 的内容:

{
  "Errors": [
    {
      "Code": "Columns.Unsupported",
      "Message": "The upload contains the following unsupported column headings: Column 1, Column 2, Column 3, Column 4."
    }
  ]
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接