![](/img/trans.png)
[英]System.Core error: “Code supposed to be unreachable” using C# Entity Framework and Linq with Expression
[英]C# Entity Framework Core: Processing of the LINQ expression failed
我们的 MySQL 数据库中有以下表:
Table club(有更多的列,但我们现在只关心Id):
Id | ...
---+----
1 | ...
表类型:
Id | GenreName
---+-----------
1 | Rock
2 | Classic
3 | Techno
和表 club2genre:
ClubId | GenreId
-------+--------
1 | 1
1 | 2
1 | 3
使用以下 MySQL 查询:
SELECT
club.Id,
GROUP_CONCAT(genre.GenreName) as Music
FROM
club
INNER JOIN club2genre
ON club2genre.clubid = club.id
INNER JOIN genre
ON genre.id = club2genre.genreid
GROUP BY
club.Id;
我们得到(如预期的)这个结果:
Id | Music
---+---------
1 | Rock,Classic,Techno
var queryResult = DbContext.Club.Join(
DbContext.Club2Genre,
club => club.Id,
club2genre => club2genre.ClubId,
(club, cg) => new
{
Id = club.Id,
GenreId = cg.GenreId
})
.GroupJoin(
DbContext.Genre,
temp => temp.GenreId,
genre => genre.Id,
(temp, genreList) => new
{
ClubId = temp.Id,
Genres = genreList.Select(genre => genre.Name)
})
.GroupBy(result => result.ClubId);
var result = result.ToList();
理论上,这个 Entity Framework Core LINQ 表达式应该是上面 MySQL 查询的 1:1 转换,其中别名为Music
( GROUP_CONCAT
)的结果列应该是一个 IEnumerable 但是在执行时抛出以下异常:
有趣的是,它只会在对queryResult
调用ToList()
时失败,所以我什至不确定 LINQ 表达式本身是问题所在。 并且(至少对我而言)错误消息似乎并没有特别有用,只是基本上说"EF Core might be buggy but also maybe not. Who knows"
。
所以我的问题是:
1.) 我正在尝试使用 LINQ 和 EF Core 做什至可能吗?
2.) 如果是这样,我的代码有什么问题,为什么会崩溃?
3.) 我该如何解决?
使用扩展函数,您可以生成一个LEFT JOIN
并创建一个展平的结果,然后可以在客户端对其进行分组以模拟GroupJoin
。
我假设返回左侧多个副本的单个查询比拆分左侧和右侧的多个查询更可取,因为这就是 LINQ to SQL 所做的,但也可以实现执行两个查询的翻译,一个用于左侧,另一个用于与左侧匹配的右侧,然后加入客户端。 这以两次查询为代价消除了重复的左侧。 您还可以通过放入Select
将每一侧缩小到仅键和结果所需的列来最小化左重复和网络流量。
public static class QueryableExt {
// implement GroupJoin for EF Core 3 by using `LEFT JOIN` and grouping on client side
public static IEnumerable<TRes> GroupJoinEF<TLeft,TRight,TKey,TRes>(
this IQueryable<TLeft> leftq,
IQueryable<TRight> rightq,
Expression<Func<TLeft,TKey>> leftKeyExp,
Expression<Func<TRight,TKey>> rightKeyExp,
Func<TLeft, IEnumerable<TRight>, TRes> resFn) =>
leftq.GroupJoin(rightq, leftKeyExp, rightKeyExp, (left, rightj) => new { left, rightj })
.SelectMany(lrj => lrj.rightj.DefaultIfEmpty(), (lrj, right) => new { lrj.left, right })
.AsEnumerable()
.GroupBy(lr => lr.left, lr => lr.right, (left, rightg) => resFn(left, rightg));
}
有了这个扩展,你的查询变成:
var queryResult = DbContext.Club
.GroupJoinEF(DbContext.Club2Genre.Join(DbContext.Genre, c2g => c2g.GenreId, g => g.Id, (c2g, g) => new { c2g.Id, g.Genre }),
c => c.Id,
cg => cg.Id,
(c, cgj) => new {
c.Id,
Music = String.Join(",", cgj.Select(cg => cg?.Genre))
}
);
但是,由于您没有在查询中使用LEFT JOIN
,因此您不需要完整的GroupJoin
实现,只需在客户端使用Join
和 group 即可:
var queryResult = DbContext.Club
.Join(DbContext.Club2Genre, c => c.Id, c2g => c2g.Id, (c, c2g) => new { c.Id, c2g.GenreId })
.Join(DbContext.Genre, cgi => cgi.GenreId, g => g.Id, (cgi, g) => new { cgi.Id, g.Genre })
.AsEnumerable()
.GroupBy(cg => cg.Id, (cId, cgg) => new { Id = cId, Music = String.Join(",", cgg.Select(cg => cg.Genre)) });
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.