我目前正在处理具有几个一对多和多对多关系的数据库,而我正在努力让ormlite正常工作。
我有一对多的关系,
var q2 = Db.From<GardnerRecord>()
.LeftJoin<GardnerRecord, GardnerEBookRecord>((x, y) => x.EanNumber == y.PhysicalEditionEan)
我需要返回具有ProductDto
嵌套列表的GardnerEBookRecord
集合。
使用SelectMult()
技术不起作用,因为在我将左连接的结果压缩为较小的集合时分页会中断,因此页面大小和偏移量都是错误的(此方法:How to return nested objects of many-to-many relationship with autoquery )
要正确进行分页,我需要能够执行以下操作:
select r.*, count(e) as ebook_count, array_agg(e.*)
from gardner_record r
left join gardner_e_book_record e
on r.ean_number = e.physical_edition_ean
group by r.id
文档中没有此示例,我一直在努力找出答案。我在OrmLite的array_agg
对象中看不到任何像Sql
一样起作用的东西。
我尝试了以下形式的变化:
var q2 = Db.From<GardnerRecord>()
.LeftJoin<GardnerRecord, GardnerEBookRecord>((x, y) => x.EanNumber == y.PhysicalEditionEan)
.GroupBy(x => x.Id).Limit(100)
.Select<GardnerRecord, GardnerEBookRecord>((x, y) => new { x, EbookCount = Sql.Count(y), y }) //how to aggregate y?
var res2 = Db.SelectMulti<GardnerRecord, GardnerEBookRecord>(q2);
和
var q2 = Db.From<GardnerRecord>()
.LeftJoin<GardnerRecord, GardnerEBookRecord>((x, y) => x.EanNumber == y.PhysicalEditionEan)
.GroupBy(x => x.Id).Limit(100)
.Select<GardnerRecord, List<GardnerEBookRecord>>((x, y) => new { x, y });
var res = Db.SqlList<object>(q2);
但是我不知道如何将GardnerEBookRecord聚合到一个列表中并保持分页和偏移正确。
这可能吗?有解决方法吗?
编辑:
我创建了一个项目,您可以运行该项目以查看问题:
https://github.com/GuerrillaCoder/OneToManyIssue
作为docker添加的数据库可以运行docker-compose up
。希望这可以显示我正在尝试做的事情
答案 0 :(得分:1)
Npgsql不支持读取未知数组或记录列类型,例如array_agg(e.*)
,失败,显示:
未处理的异常:System.NotSupportedException:字段'ebooks'具有Npgsql当前未知的类型(OID 347129)。
但是它确实支持使用array_agg(e.id)
读取整数数组,您可以改为查询:
var q = @"select b.*, array_agg(e.id) ids from book b
left join e_book e on e.physical_book_ean = b.ean_number
group by b.id";
var results = db.SqlList<Dictionary<string,object>>(q);
这将返回一个Dictionary Dynamic Result Set,您需要将其合并成一个不同的ID集合以查询所有引用的电子书,例如:
//Select All referenced EBooks in a single query
var allIds = new HashSet<int>();
results.Each(x => (x["ids"] as int[])?.Each(id => allIds.Add(id)));
var ebooks = db.SelectByIds<EBook>(allIds);
然后,您可以创建id => Ebook
的字典映射,并使用该映射使用每行的ID填充电子书实体的集合:
var ebooksMap = ebooks.ToDictionary(x => x.Id);
results.Each(x => x[nameof(ProductDto.Ebooks)] = (x["ids"] as int[])?
.Where(id => id != 0).Map(id => ebooksMap[id]) );
然后您可以使用ServiceStack AutoMapping Utils将每个对象字典转换为产品DTO:
var dtos = results.Map(x => x.ConvertTo<ProductDto>());