如何用LINQ实现PostgreSQL数组列展开并获取唯一标签?
问题:PostgreSQL中用纯LINQ获取string[]列的所有唯一标签
在PostgreSQL数据库中有一张带string[]类型标签列的表,想要获取所有唯一标签。最初尝试使用:
.SelectMany(d => d.Tags).Distinct()
但出现错误:
The LINQ expression 'd => d.Tags' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'.
目前采用的客户端处理方案:
var tagsArrays = await _context.MyTable .Select(d => d.Tags) .ToListAsync(); var knownTags = tagsArrays .SelectMany(a => a) .Distinct() .ToList();
已知可通过原生SQL结合UNNEST实现,但代码中其他场景未使用SQL,希望避免该方式,询问能否用纯LINQ风格的查询实现需求。
回答
可以通过Npgsql.EntityFrameworkCore.PostgreSQL提供的扩展方法实现纯LINQ风格的服务端查询,无需手写原生SQL:
方案1:使用NpgsqlDbFunctionsExtensions.Unnest
using Microsoft.EntityFrameworkCore; // 直接在数据库端完成数组展开与去重 var knownTags = await _context.MyTable .SelectMany(d => NpgsqlDbFunctionsExtensions.Unnest(_context, d.Tags)) .Distinct() .ToListAsync();
这个写法会被EF Core翻译为PostgreSQL的UNNEST原生函数,所有操作在数据库端执行,避免了客户端拉取大量数据的性能损耗。
方案2:直接使用SelectMany(需较新版本依赖)
如果你的EF Core版本在5.0及以上,且Npgsql.EntityFrameworkCore.PostgreSQL版本匹配,直接使用最初的写法也能被正确翻译:
var knownTags = await _context.MyTable .SelectMany(d => d.Tags) .Distinct() .ToListAsync();
之前报错大概率是因为依赖版本过低,升级到较新版本即可解决。
内容的提问来源于stack exchange,提问作者underdunk
相关产品推荐
相关产品推荐

