简体   繁体   English

由.Include()相关实体创建的内部联接的IQueryable Count()方法问题

[英]IQueryable Count() method issue with Inner Join created by .Include() related entities

IQueryable<EntityOne> query = entities.EntityOne
    .Include(t => t.EntityRelated1)
    .Include(t => t.EntityRelated2)
    .AsQueryable();

The query generated in "query" variable : 在“查询”变量中生成的查询:

SELECT 
[Extent1].[Id] AS [IdEntityOne], 
 ...
[Extent2].[Id] AS [IdEntityRelatedOne], 
...
[Extent3].[Id] AS [IdEntityRelatedTwo], 
...
FROM   [dbo].[EntityOne] AS [Extent1]
   INNER JOIN [dbo].[EntityRelatedOne] AS [Extent2]
       ON [Extent1].[IdRelatedOne] = [Extent2].[Id]
   INNER JOIN [dbo].[EntityRelatedTwo] AS [Extent3]
       ON [Extent1].[IdRelatedTwo] = [Extent3].[Id]

After that, on C# code those are the result of counting: 之后,在C#代码上,这些是计数的结果:

var wrongCount = query.Count(); // Returns 295
var correctCount = query.AsEnumerable().Count(); // Returns 10

The 295 count is the full EntityOne set numbers of registers. 295个计数是EntityOne集的全部寄存器数。 (wrong) (错误)

The 10 Count is the desired count after Inner Join. 10计数是内部加入后所需的计数。

It sounds like the IQueryable.Count() is counting before executing the InnerJoin on database. 听起来IQueryable.Count()正在对数据库执行InnerJoin之前正在计数。 I don't want to generate the IEnumerable since I hope the count to be executed on Sql Server together with the inner join. 我不想生成IEnumerable因为我希望该计数与内部Sql Server一起在Sql Server上执行。

UPDATE 1 更新1

Trying to manually execute the inner join: 尝试手动执行内部联接:

IQueryable<EntityOne> query2 = entities.EntityOne.Join(entities.EntityTwo,
     eone=> eone.IdRelatedOne, en => en.Id,
     (x, y) => x);

The SQL code generated in "query2" is : 在“ query2”中生成的SQL代码是:

SELECT 
[Extent1].[Id] AS [Id], 
...
FROM [dbo].[EntityOne] AS [Extent1]

As you can see, the related entity is not included on Inner Join forced by linq Join statement. 如您所见,在linq Join语句强制的内部联接中不包含相关实体。

Update 2 更新2

I dont know if it matters but, the IdEntityRelated1 on EntityOne is a required property, plus its not a foreign key on database, just a Integer field that stores the Id of the related entity. 我不知道这是否重要,但是EntityOne上的IdEntityRelated1是必需属性,加上它不是数据库上的外键,只是存储相关实体ID的Integer字段。 (Im working with POCO classes with Database First) (我正在与数据库优先一起使用POCO类)

I have another working sources where fields but they're nullable integers instead of required. 我在字段中有另一个工作源,但它们是可为空的整数,而不是必需的。 Maybe should I not try to do an Include to force Inner Join between required relationships? 也许我不应该尝试在所需关系之间进行包含以强制内部联接吗?

You have a required association, but the expected objects are not present in the database. 您具有必需的关联,但是数据库中不存在预期的对象。

But let's first see what EF does. 但首先让我们看看EF的作用。

In the first count ... 一次 ...

var wrongCount = query.Count();

...the Include s are ignored. ... Include被忽略。 There's no reason to execute them because EF has been told that the referred objects ( EntityRelated1 and EntityRelated2 are mandatory, so inner joins are expected to find the related records . If they do, EF figures it may as well just count entities.EntityOne and skip the rest. The Includes are only going to make the query more expensive and they don't affect the result. 没有理由执行它们,因为已经告知EF所引用的对象( EntityRelated1EntityRelated2是强制性的,因此内部联接应查找到相关记录 。如果这样做,EF可能认为它也可以只对entities.EntityOne计数。 Includes只会使查询更昂贵,并且不会影响结果。

You can check that by monitoring the SQL that's executed for the count. 您可以通过监视为计数而执行的SQL进行检查。 That's not the SQL generated when you look at query only! 仅查看query时,这不是生成的SQL! It's probably something that simply boils down to 大概可以归结为

SELECT COUNT(*) FROM [dbo].[EntityOne]

So the first count returns a correct count of all EntityOne records in the database. 因此,第一个计数返回数据库中所有EntityOne记录的正确计数。

For the second count you force execution of the entire query that's stored in the query variable, the SQL statement that you show. 对于第二个计数,您强制执行存储在query变量(显示的SQL语句)中的整个查询。 Then you count its results in memory – and it returns 10 . 然后,将其结果计数在内存中-并返回10 This means that the query with the inner joins does actually return 10 records. 这意味着带有内部联接的查询实际上返回了10条记录。 That, in turn, can only mean one thing: there are 285 EntityOne.IdRelatedOne values that don't point to an existing EntityRelatedOne record. 反过来,这仅意味着一件事:有285个EntityOne.IdRelatedOne值不指向现有的EntityRelatedOne记录。 But you mapped the association as required, so EF generates an inner join. 但是您根据需要映射了关联,所以EF生成了一个内部联接。 An outer join would also return 295. 外部联接也将返回295。

Include is not a LINQ method proper, is an EntityFramework extension designed to do eager loading and not much else. Include不是适合的LINQ方法,而是EntityFramework扩展,旨在进行急切的加载,仅此而已。 Include s are lost if the query shape changes : 如果查询形状更改,则 Include 会丢失

When you call the Include method, the query path is only valid on the returned instance of the IQueryable of T. Other instances of IQueryable of T and the context itself are not affected. 当您调用Include方法时,查询路径仅在T的IQueryable实例的返回实例上有效。T的IQueryable的其他实例和上下文本身均不受影响。

Specifically this means that, for instance aggregates on top of the Include d IQueryable<T> are going to loose the Include (which is exactly what you see). 具体来说,这意味着,例如,在Include d IQueryable<T>之上的聚合将失去Include (正是您所看到的)。

See Tip 22 - How to make Include really Include , IQueryable.Include() gets ignored , Include in following query does not include really and many more. 请参见技巧22-如何使Include真正包含IQueryable.Include()被忽略以下查询中的Include并不包含真正的更多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM