Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.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# Linq到实体使用SelectMany跳过OrderBy_C#_Linq_Entity Framework - Fatal编程技术网

C# Linq到实体使用SelectMany跳过OrderBy

C# Linq到实体使用SelectMany跳过OrderBy,c#,linq,entity-framework,C#,Linq,Entity Framework,我在使用LINQtoEntity(代码优先)时遇到了一种非常奇怪的行为 我所有的实体、上下文和数据库都运行良好,这是一个持续进行的项目,开发、更新和在线两年。我使用的是.NET4.5,EF5。对于该特定查询,LazyLoading被禁用(激活它不会改变任何事情) 我有以下表格(我只提到与该问题相关的内容): 游戏,哪个举行游戏 Press,其中包含有关游戏的新闻文章 PressTypes,用于保存新闻文章的类别 Press_Games,它定义了Press to Games之间的一对多(一篇文章

我在使用LINQtoEntity(代码优先)时遇到了一种非常奇怪的行为

我所有的实体、上下文和数据库都运行良好,这是一个持续进行的项目,开发、更新和在线两年。我使用的是.NET4.5,EF5。对于该特定查询,LazyLoading被禁用(激活它不会改变任何事情)

我有以下表格(我只提到与该问题相关的内容):

  • 游戏,哪个举行游戏
  • Press,其中包含有关游戏的新闻文章
  • PressTypes,用于保存新闻文章的类别
  • Press_Games,它定义了Press to Games之间的一对多(一篇文章可以是关于多个游戏的)
关于表及其匹配实体:

  • 游戏有很多字段,但假设它只包含两个字段:ID(guid)和Name,即游戏的名称
  • Press还有许多字段,其中我们有:ID(guid)、CategoryID(guid)和UpdateDate(DateTime),它们表示文章最后一次更新的时间
  • Press实体有一个Category对象和一个IEnumerable对象
  • 游戏实体没有按键导航属性(以这种方式设计和需要)
  • PressTypes是新闻文章类别的列表,具有ID(guid)
  • Press_游戏有两个字段,GameID(guid)和PressID(guid)
我需要得到5个游戏的列表,这些游戏与特定类别的最新新闻文章相关联。我通过以下查询检索它们:

Context.Press
    .Where(press => press.Category.ID == MagicValues.ReviewGuid)) // MagicValues.ReviewGuid returns a Guid
    .OrderByDescending(press => press.UpdateDate)
    .SelectMany(press => press.Games)
    .Take(5);
生成的列表将获得游戏列表,但不是与预期的时间顺序相匹配的游戏列表。使用LINQPad,我注意到生成的查询如下所示:

SELECT TOP (5) 
[Join1].[ID] AS [ID], 
[Join1].[Name] AS [Name], 
FROM  [dbo].[Press] AS [Extent1]
INNER JOIN  (SELECT [Extent2].[PressID] AS [PressID], [Extent3].[ID] AS [ID] /* lots of selected fields */
    FROM  [dbo].[Press_Games] AS [Extent2]
    INNER JOIN [dbo].[Games] AS [Extent3] ON [Extent3].[ID] = [Extent2].[GameID] ) AS [Join1] ON [Extent1].[ID] = [Join1].[PressID]
WHERE cast('b5c18183-14e2-4bf2-b4e1-641b56694c55' as uniqueidentifier) = [Extent1].[CategoryID]
没有订单。如果我稍微更改查询以选择文章而不是游戏,我将按照预期顺序获得适当的文章列表及其游戏:

Context.Press
    .Include(press => press.Games)
    .Where(press => press.Category.ID == MagicValues.ReviewGuid)) // MagicValues.ReviewGuid returns a Guid
    .OrderByDescending(press => press.UpdateDate)
    .Take(25);
生成的SQL查询变为:

SELECT 
[Project2].[C1] AS [C1], 
[Project2].[ID] AS [ID], 
[Project2].[Name] AS [Name], 
FROM ( 
    /* Lots of irrelevant stuff with JOINs and SELECTs */
)  AS [Project2]
ORDER BY [Project2].[UpdateDate] DESC, [Project2].[ID] ASC, [Project2].[C2] ASC
我从后面拿到了订单(这或多或少是它工作时所期待的)

所以(最后)我的问题是:这是预期的行为还是一个bug?

我在想,因为我使用的是SelectMany,EF似乎认为只需要游戏表,因此忽略了新闻上的OrderBy。这可能有道理,但似乎有点违反直觉


我会找到一种绕过这个问题的方法(除非有一个干净的解决方案),但我对这个行为和解释很好奇

这是关于EF的内部机制,所以我不得不在这里猜测。看来英孚聪明地构建了最经济的查询可能导致它在这里出错

问题1 让我们看看一些简化的查询,它们演示了发生了什么

首先,裸骨形态

from p in Context.Press
from g in p.Games
select g
这相当于
Context.Press.SelectMany(Press=>Press.Games)
。顺便说一句,请注意,
Press
Game
之间存在多对多关联,因为您有一个连接表
Press\u Games
。您可以将相同的
游戏
分配给多个
按键
对象(尽管您可能不这样做)

EF的查询生成功能经常被贬低,但至少它足够聪明,可以看到在这个简单的查询中,它只需要表格
Games
Press\u Games
来生成输出<代码>按不在SQL查询中

如果添加谓词

from p in Context.Press
from g in p.Games
where p.Category.ID == guid
select g
…您将看到,
Press
被加入以满足谓词。SQL查询仅包含联接和谓词所需的
Press
字段。另一个优化是在SQL查询中使用
Press.CategoryID
,而不加入
Category

因此,EF在最小化SQL查询中访问的表和字段的数量方面投入了大量精力。这项工作似乎是由输出驱动的:否
返回数据,否
选择数据

不,让我们将顺序添加到基本查询中(忽略降序部分,这在这里不是必需的)

orderby
子句没有任何效力!您将看到,生成的SQL无论有无都是相同的

我认为EF“认为”输出仅与
Games
有关–《p.Games中g的
是被要求的–因此查询中的所有其他内容都是关于如何获取数据,而不是如何塑造输出

但是如果你这样做了

from p in Context.Press
from g in p.Games
orderby p.UpdateDate
select g
…排序遵循请求的输出并应用。再一次,我不得不猜测英孚的内在逻辑,但我认为这就是发生的事情

我使用查询语法,因为在fluent中,后一个LINQ语句会转换为一个更为详细的
SelectMany
重载。但是此查询返回您所查找的数据。

在我看来,
orderby
的位置应该无关紧要(正如您所说,这是违反直觉的),但是,好吧,它确实如此

问题2
这里,
Press
是请求的输出,因此应用任何排序都是有意义的,不管它在查询中的位置如何。请注意,选择包含
Games
Press
与查询1中发生的情况有很大不同。

一些有类似问题的旧MSDN线程-感谢您提供此详细答案。你的建议也很有效。。。直到我在混合中加入一个Distinct():var games=from p in Press。。。游戏。独特()。采取(5);但在这个问题上,我认为这更多的是来自SQL Server的约束,因为它不能在不属于SELECT DISTINCT的字段上进行排序。然而,如果我“强制”EF对这个进行第一批处理,并对这个应用Distinct(),我会得到预期的结果:games.take(100.Distinct().take(5);生成的SQL查询与我在集合上运行SqlQuery时编写的非常相似。它也是合乎逻辑的:
D
from p in Context.Press
from g in p.Games
orderby p.UpdateDate
select g