将来自 JSON 数组对象字段的数据与另一个 table 合并
Joining data from JSON array object field with another table
比方说,我在 Postgre 数据库上有两个 table,如下所示:
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 映射到以下模型:
[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 table:
的数据样本
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 数组。我对如何使用用户的详细信息加入团队->成员->详细信息感到困惑 table。
这是我的查询:
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 引擎的 additional/extension,因为我也在这个问题标签上添加了。
问题在于您对 team.Members
的投影,它是 JSON 属性 而不是 EF 导航 - 这无法转换为 SQL 以在PostgreSQL.由于这是最终投影,因此应该简单地得到 client-evaluated,但 EF 似乎有一个错误(打开 https://github.com/dotnet/efcore/issues/22161 进行跟踪)。
如果目的是将此设置为 client-evaluate,只需在投影前放置一个 AsEnumerable - 这应该会使错误消失。否则,
理论上,这可以通过将 JSON 数组投影转换为 json_array_elements
(see PG docs) 来完成,但提供者随时都不可能做到这一点很快。
比方说,我在 Postgre 数据库上有两个 table,如下所示:
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 映射到以下模型:
[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 table:
的数据样本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 数组。我对如何使用用户的详细信息加入团队->成员->详细信息感到困惑 table。
这是我的查询:
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 引擎的 additional/extension,因为我也在这个问题标签上添加了。
问题在于您对 team.Members
的投影,它是 JSON 属性 而不是 EF 导航 - 这无法转换为 SQL 以在PostgreSQL.由于这是最终投影,因此应该简单地得到 client-evaluated,但 EF 似乎有一个错误(打开 https://github.com/dotnet/efcore/issues/22161 进行跟踪)。
如果目的是将此设置为 client-evaluate,只需在投影前放置一个 AsEnumerable - 这应该会使错误消失。否则,
理论上,这可以通过将 JSON 数组投影转换为 json_array_elements
(see PG docs) 来完成,但提供者随时都不可能做到这一点很快。