【问题标题】:Joining data from JSON array object field with another table将来自 JSON 数组对象字段的数据与另一个表连接起来
【发布时间】:2020-08-20 19:16:07
【问题描述】:

假设,我在 Postgre 数据库中有两个表,如下所示:

CREATE TABLE "MST"."Users" (
  "Id" uuid NOT NULL DEFAULT uuid_generate_v4(),
  "Uid" varchar(32) COLLATE "pg_catalog"."default" NOT NULL,
  "Pid" varchar(100) COLLATE "pg_catalog"."default" NOT NULL,
  "Details" jsonb,
  "Contacts" jsonb,
  "Trackers" jsonb NOT NULL,
  "Configurations" jsonb,
  PRIMARY KEY ("Id"),
  UNIQUE ("Uid")
);

CREATE TABLE "MST"."Teams" (
  "Id" uuid NOT NULL DEFAULT uuid_generate_v4(),
  "Details" jsonb NOT NULL,
  "Members" jsonb,
  "Trackers" jsonb NOT NULL,
  PRIMARY KEY ("Id")
);

这两个表都映射到以下模型:

    [Table("Users", Schema = "MST")]
    public partial class Users
    {
        [Key]
        public Guid Id { get; set; }
        
        [Required]
        [StringLength(32)]
        public string Uid { get; set; }
        
        [Required]
        [StringLength(100)]
        public string Pid { get; set; }

        [Column(TypeName = "jsonb")]
        public UserDetailsModel Details { get; set; }

        [Column(TypeName = "jsonb")]
        public UserContactsModel Contacts { get; set; }

        [Required]
        [Column(TypeName = "jsonb")]
        public TrackersModel Trackers { get; set; }

        [Column(TypeName = "jsonb")]
        public UserConfigurationsModel Configurations { get; set; }
    }

    [Table("Teams", Schema = "MST")]
    public partial class Teams
    {
        [Key]
        public Guid Id { get; set; }

        [Required]
        [Column(TypeName = "jsonb")]
        public TeamDetailsModel Details { get; set; }
        
        [Column(TypeName = "jsonb")]
        public List<TeamMembersModel> Members { get; set; }

        [Required]
        [Column(TypeName = "jsonb")]
        public TrackersModel Trackers { get; set; }
    }

    // Childs classes
    public class TeamMembersModel
    {
        [Required(ErrorMessage = @"Member ""User ID"" is required and can not be empty.")]
        [StringLength(maximumLength: 32, MinimumLength = 3, ErrorMessage = @"Member ""User ID"" length must be between 3 and 32 chars.")]
        public string Uid { get; set; }

        public bool IsLead { get; set; } = false;

        public UserDetailsModel Details { get; set; }
    }

    public UserContactModel { 
        ...some properties...
    }

    public TrackersModel { 
        ...some properties...
    }

    public UserDetailsModel { 
        ...some properties...
    }

以下是Teams表中的数据样本:

INSERT INTO "MST"."Teams"("Id", "Details", "Members", "Trackers") VALUES ('daf0e3d3-78bf-443b-8b0b-6f74d2eabd7f', '{"Name": "My First Team", "Files": [], "Notes": null, "Photo": null}', '[{"Uid": "fadhly.permata", "IsLead": true}, {"Uid": "humaira.permata", "IsLead": false}]', '{"Status": "RG", "Created": {"At": "2020-08-14T12:15:59.4175028+00:00", "By": "SYSTEM"}, "Updated": null}');

INSERT INTO "MST"."Teams"("Id", "Details", "Members", "Trackers") VALUES ('538f1d58-01cb-4120-b89a-ea25bfacaa25', '{"Name": "My Second Team", "Files": [], "Notes": null, "Photo": null}', '[{"Uid": "fadhly.permata", "IsLead": true, "Details": null}]', '{"Status": "RG", "Created": {"At": "2020-08-19T10:51:44.5128139+00:00", "By": "fadhly.permata"}, "Updated": null}');

正如您在我的数据库数据中看到的,Members 字段与 JSON 数组一起存储。我对如何加入 Teams->Members->Details 和用户表中的详细信息感到困惑。

这是我的查询:

from
    team in _manager.DbContext.Teams

where
    team.Trackers.Status != "DE"

orderby
    team.Details.Name

select
    new Models.Teams
    {
        Id = team.Id,
        Details = team.Details,
        Trackers = team.Trackers,
        Members = team.Members.Select(
            x => new TeamMembersModel { 
                Uid = x.Uid, 
                IsLead = x.IsLead, 
                Details = _manager.DbContext.Users.First(y => y.Uid == x.Uid).Details 
            }
        )
            .ToList()
    };

但我对上述查询没有运气,并收到以下错误消息: "Object reference not set to an instance of an object."

也许,我遗漏了一些东西,但不确定它在哪里。


注意: 我正在使用 NPGSQL 作为 EF 引擎的附加/扩展,因为我也在这个问题标签上添加了。

【问题讨论】:

  • LINQ to SQL/EF 不支持 JSON 字段。您可能需要使用存储过程或其他自定义 SQL。
  • @NetMage 感谢您的回复兄弟。起初,我和你一样想。但是在听了 DB 上的 JSON 技术之后,我尝试深入挖掘我的知识。我找到了this。有了这个引擎,我们可以轻松管理 JSON。我对另一个表没有问题,但是现在当我想从另一个表中获取详细信息时,我被一个 JSON 数组困住了。

标签: postgresql linq linq-to-sql npgsql .net-core-3.1


【解决方案1】:

问题在于您对team.Members 的投影,这是一个 JSON 属性而不是 EF 导航 - 这无法转换为 SQL 以便在 PostgreSQL 中进行处理。由于这是最终的预测,这应该简单地得到客户评估,但 EF 似乎有一个关于此的错误(打开 https://github.com/dotnet/efcore/issues/22161 进行跟踪)。

如果目的是让客户评估,只需在投影之前放置一个 AsEnumerable - 这应该会使错误消失。否则,

理论上,这可以通过将 JSON 数组投影转换为 json_array_elements (see PG docs) 来完成,但提供者极不可能很快做到这一点。

【讨论】:

  • 抱歉我的回复晚了。并感谢您的回复。这是我在 DB 上使用 JSON 的第一次体验。我懒得阅读文档,只是认为 NPGSQL 将能够获取“详细信息”。所以,经过几天的调试和测试,我知道了真相(LOL)。主要重点是,我想根据“详细信息”值过滤数据。由于无法正确获取我的结构,因此我更改了数据库结构以满足我的需要。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-12-17
  • 1970-01-01
  • 2013-01-24
  • 2013-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多