为什么LINQ GroupBy在ToArray()之前会产生不同的结果?

时间:2014-02-07 01:37:35

标签: .net linq entity-framework group-by toarray

我正在使用Entity Framework从SQL中提取一些数据。

我写了一些看起来像下面代码段的代码。请注意,Something是数据库中的varchar值。此外,我认为Something中的每个值都包含十个数字,一个连字符,然后两个数字,例如“0123456789-01”,这可能是相关的。 (不要提醒我这是糟糕的设计;我不是这个数据库的架构师。)

var X = Entities.MyView
    .Select(x => x.Something)
    .Distinct();
// 5850 elements

var Y = Entities.MyView
    .GroupBy(x => x.Something);
// 5850 elements

var Z = Entities.MyView
    .ToArray()
    .GroupBy(x => x.Something);
// 5727 elements

// Added in response to user995219's Answer
var ZZ = Entities.MyView
    .GroupBy(x => x.Something)
    .ToArray();
    // 5850 elements

第一个语句从视图Something中提取MyView列的不同值。它得到了结果5850元素,这是我所期望的。

第二个语句将整个视图拉下来并按Something的唯一值对其进行分组,产生5850个分组,这正是我所期望的。

第三个语句完全相同,只是它对来自ToArray的值调用MyView。通常,当我希望调用代码使用整个数据并且不想处理任何延迟加载SNAFU时,我会这样做。但是,当我在调试器中运行此代码时,第三个语句会产生5727个分组,比我预期的少123个。

编辑:第四个语句只是颠倒GroupByToArray方法链接的顺序。做这个小改动,我得到了我期望的行数,但是这个问题无法通过这种方式解决的真正问题是因为真正的问题是将来自此SQL调用的数据与其他数据相关联并将它们返回到单个对象中的代码

我希望了解使用ToArray会导致我得到错误数量的结果。

后续行动:为了回应user995219的回答,我重新编写了MyView,以便它有一个额外的列:SomethingInt,它只包含一个32位整数通过省略Something中的连字符并将结果视为单个整数。然后,LINQ代码在新建的整数上执行GroupBy

然而,即使有了这个改变,我仍然遇到同样的问题。

var A = Entities.MyView
    .ToArray();
// Returns 17893 elements, the same as if I ran SELECT * FROM MyView

var array0 = A.Select(x => x.SomethingInt).Distinct();
// Returns 5727 elements when I expect 5850

在SQL中,SELECT COUNT(DISTINCT(SomethingInt)) FROM MyView;返回5850,正如我所料。

这应该在.net框架中进行任何类型的字符串比较,但问题仍然存在。

2 个答案:

答案 0 :(得分:5)

ToArray语句执行查询,并使用字符串相等比较器在内存中执行group by。 前两个语句在SQL级别执行组。 有区别: String Comparison differences between .NET and T-SQL?

特别是关于整理。

答案 1 :(得分:2)

我找到了答案。 user995219的答案很有用,但没有完整的解释。

显然,LINQ方法会检查它们正在运行的内容。就我而言,我正在使用Entity Framework生成的类。它们具有“实体密钥”,允许.net框架区分具有相同内容的两行和同一行的两个实例。

在我的情况下,我使用了一个复杂的视图,.net框架错误地推断出实体键,然后丢弃了行,因为它认为它们是相同的。

我的解决方案是修改我的视图,以便有一个唯一标识每一行的GUID,并将GUID用作实体密钥。