Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 是否可以提示EntityFramework Core使用内部联接而不是EXISTS子查询来查询导航属性集合条件?_C#_Sql Server_Entity Framework Core - Fatal编程技术网

C# 是否可以提示EntityFramework Core使用内部联接而不是EXISTS子查询来查询导航属性集合条件?

C# 是否可以提示EntityFramework Core使用内部联接而不是EXISTS子查询来查询导航属性集合条件?,c#,sql-server,entity-framework-core,C#,Sql Server,Entity Framework Core,我有四个表格:用户、歌曲、流派和收藏流派 用户可以选择自己喜欢的音乐类型,当他们导航到仪表板时,会看到他们喜欢的音乐类型中的歌曲列表 我有以下EF核心代码来实现这一点: dbContext .Songs .Include(song => song.Genre) .Where(song => song.Genre.FavoriteGenres.Any(favoriteGenre => favoriteGenre.UserId == userId))

我有四个表格:用户、歌曲、流派和收藏流派

用户可以选择自己喜欢的音乐类型,当他们导航到仪表板时,会看到他们喜欢的音乐类型中的歌曲列表

我有以下EF核心代码来实现这一点:

dbContext
    .Songs
    .Include(song => song.Genre)
    .Where(song => song.Genre.FavoriteGenres.Any(favoriteGenre => favoriteGenre.UserId == userId))
    .OrderBy(song => song.CreatedDateTimeOffset)
    .ToListAsync(cancellationToken);
输出的查询(工作正常)是:

我只是想知道是否有可能提示EF core生成以下查询,我认为这可能更为优化(尽管我希望别人告诉我我错了!):


执行计划看起来非常相似,但老实说,我不是阅读计划的专家。任何形式的帮助都将非常感谢:)

虽然@IvanStoev的评论是正确的,并且应该没有必要重写查询,但是如果您仍然关心不同的查询生成,一种简单的方法是对表中的includes重新排序。由于最终不会将歌曲作为根实体,而是最喜爱的类型,因此您可能需要重新排列返回的实体:

var result=context.favoriteGenes
.Include(favoritegree=>favoritegree.Genre)
.然后包括(流派=>流派.歌曲)
.Where(favoritegree=>favoritegree.UserId==UserId)
.AsEnumerable()//FavoriteGene.Genre.Songs)
.OrderBy(song=>song.CreatedDateTimeOffset)
.ToList();
这将导致生成以下SQL:

选择[f].[UserId]、[f].[GenreId]、[g].[Id]、[g].[Name]、[s].[Id]、[s].[CreatedDateTimeOffset]、[s].[GenreId]、[s].[Title]
从[FavoriteTyres]AS[f]
[f].[GenreId]=[g].[Id]上的[g]作为内部联接[Genres]
在[g].[Id]=[s].[GenreId]上以[s]的身份左键加入[Songs]
其中[f].[UserId]=@\uu UserId\u 0
按[f].[UserId]、[f].[GenreId]、[g].[Id]、[s].[Id]排序

EXISTS几乎总是性能更好,但是,在大多数情况下,SQL Server足够聪明,可以为两个查询字符串生成相同的查询计划,因此您只需更改发送到SQL Server的文本,而不会真正影响到在到达后生成的查询计划

但是,如果确实需要,您可以使用
,让它生成所需的查询。包括收藏夹的
,如果不希望在结果中包含收藏夹列
。请仅选择所需的列,例如:

dbContext
    .Songs
    .Include(song => song.Genre)
        .ThenInclude(genre => genre.FavoriteGenres)
    .Where(song => song.Genre.FavoriteGenres.Any(favoriteGenre => favoriteGenre.UserId == userId))
    .Select(song => new {
        song.Id,
        song.Title,
        song.Genre.Id,
        song.Genre.Name
    })
    .OrderBy(song => song.CreatedDateTimeOffset)
    .ToListAsync(cancellationToken);


@CodingYoshi谢谢你!由于执行计划如此相似,并且基于您链接中的信息,我认为我可以保持原样。我会继续提问,以防有人对直接问题有答案(即:暗示EF core使用内部连接)。我真的很感谢你的帮助!EFC查询转换不能“提示”。EFC的职责是创建有效的SQL,返回LINQ查询所描述的正确结果。选择最佳执行计划是数据库查询优化器(CBO)的职责。在过去,当数据库有RBO而不是CBO时,使用编写SQL的方式来控制执行计划。现在,无论您是使用
join
还是使用相关
where
都不重要,同样的
存在(…)
vs
in(select…
等。
SELECT [s].[Id], [s].[Title], [s].[CreatedDateTimeOffset], [g].[Id], [g].[Name]
FROM [Songs] AS [s]
INNER JOIN [Genres] AS [g] ON [s].[GenreId] = [g].[Id]
INNER JOIN [FavoriteGenres] AS [f] ON [f].[GenreId] = [g].[Id]
WHERE [f].[UserId] = @__userId_0
ORDER BY [s].[CreatedDateTimeOffset] DESC
dbContext
    .Songs
    .Include(song => song.Genre)
        .ThenInclude(genre => genre.FavoriteGenres)
    .Where(song => song.Genre.FavoriteGenres.Any(favoriteGenre => favoriteGenre.UserId == userId))
    .Select(song => new {
        song.Id,
        song.Title,
        song.Genre.Id,
        song.Genre.Name
    })
    .OrderBy(song => song.CreatedDateTimeOffset)
    .ToListAsync(cancellationToken);
dbContext
    .Songs
    .Include(song => song.Genre)
        .ThenInclude(genre => genre.FavoriteGenres.Select(favoriteGenre => favoriteGenre.UserId == userID)
    .Select(song => new {
        song.Id,
        song.Title,
        song.Genre.Id,
        song.Genre.Name
    })
    .OrderBy(song => song.CreatedDateTimeOffset)
    .ToListAsync(cancellationToken);