Npgsql使用GROUP BY时array_agg列类型<unknown>的解决方法
解决PostgreSQL中array_agg返回类型的读取问题
遇到这种情况很正常,因为你用array_agg(e)聚合的是整个e_book表的行,PostgreSQL会把这个结果识别为自定义行类型数组(也就是e_book[]),但Npgsql默认没有映射这个数据库行类型到你的.NET对象,所以才会显示<unknown>。下面给你两种实用的解决方案:
方案1:用JSON聚合代替行类型聚合(最简单)
直接把聚合的行转成JSON数组,Npgsql对JSON类型的支持很友好,不需要额外配置。修改你的SQL语句:
select b.*, json_agg(e) as ebooks from book b left join e_book e on e.physical_book_ean = b.ean_number group by b.id
然后在读取数据的时候,你可以根据自己的JSON库选择方式:
- 用System.Text.Json:
while (reader.Read()) { // 读取book字段 var bookId = reader.GetInt32("id"); var eanNumber = reader.GetString("ean_number"); var title = reader.GetString("title"); // 读取ebooks数组 JsonElement[] ebooks = null; if (!reader.IsDBNull(reader.GetOrdinal("ebooks"))) { ebooks = reader.GetFieldValue<JsonElement[]>("ebooks"); // 遍历处理每个电子书 foreach (var ebook in ebooks) { var ebookId = ebook.GetProperty("id").GetInt32(); var format = ebook.GetProperty("format").GetString(); // ...其他字段 } } }
- 用Newtonsoft.Json:
while (reader.Read()) { // 读取book字段... JArray ebooks = null; if (!reader.IsDBNull(reader.GetOrdinal("ebooks"))) { ebooks = JArray.Parse(reader.GetString("ebooks")); foreach (var ebook in ebooks) { var ebookId = ebook["id"].Value<int>(); // ...处理其他字段 } } }
方案2:注册复合类型实现强类型读取(类型安全)
如果你希望直接映射到.NET的EBook[]数组,需要先让Npgsql识别PostgreSQL的e_book行类型。
步骤1:定义对应的.NET类
public class EBook { public int Id { get; set; } public string Ean { get; set; } public string Title { get; set; } public string Format { get; set; } public string PhysicalBookEan { get; set; } }
步骤2:注册复合类型
在打开数据库连接之前,注册这个类型映射:
// 全局注册,整个应用程序只需一次 NpgsqlConnection.GlobalTypeMapper.MapComposite<EBook>("e_book");
步骤3:读取数据
现在你可以直接读取强类型数组了:
while (reader.Read()) { // 读取book字段... EBook[] ebooks = null; var ebooksOrdinal = reader.GetOrdinal("ebooks"); if (!reader.IsDBNull(ebooksOrdinal)) { ebooks = reader.GetFieldValue<EBook[]>(ebooksOrdinal); // 直接使用强类型对象 foreach (var ebook in ebooks) { Console.WriteLine($"EBook ID: {ebook.Id}, Format: {ebook.Format}"); } } }
两种方案对比
- 方案1:无需额外配置,灵活度高,适合快速开发或者需要处理动态结构的场景。
- 方案2:类型安全,编译时就能检查字段错误,适合大型项目或者强类型要求高的场景。
内容的提问来源于stack exchange,提问作者Guerrilla
相关产品推荐
相关产品推荐

