2014-02-07 2 views
5

Я извлекаю некоторые данные из SQL с помощью Entity Framework.Почему LINQ GroupBy производит разные результаты, когда предшествует ToArray()?

Я написал код, который выглядит как фрагмент ниже. Обратите внимание, что Something - это значение varchar из базы данных. Более того, я думаю, что может быть уместно, что каждое значение в Something состоит из десяти цифр, дефиса, а затем еще двух цифр, например «-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. Обычно я делаю это, когда ожидаю, что код вызова будет использовать всю информацию и не хочет иметь дело с любыми Lazy Loading SNAFU. Однако, когда я запускаю этот код в отладчике, этот третий оператор дает 5727 групп, 123 меньше, чем я ожидаю.

Edit: Четвертый оператор просто меняет порядок GroupBy и ToArray метод построения цепочки. Сделав это небольшое изменение, я получаю количество строк, которые я ожидаю, но реальная проблема, что этот вопрос не может быть решён таким образом, потому что в реальной проблеме есть код, который связывает данные из этого SQL-вызова с другими данными и возвращает их в одном объекте ,

Я хочу понять, как это происходит, поскольку использование ToArray заставляет меня получить неправильное количество результатов.

Последующие меры: В ответ на ответ user995219, я переписал MyView так, что он имеет дополнительный столбец: SomethingInt, который просто containins 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 из изображения, но проблема сохраняется.

+0

имеет третий счетчик правильного счета перед GroupBy? группе по требованию IEqualityComparer для abjects, когда делаете это в памяти, однако ваша группа по ключу является примитивным типом, тогда как вы имеете дело с entityframework, можете ли вы ответить на это: [что такое 'EdmFunctions' для?] (http://stackoverflow.com/questions/21607456/what-are-edmfunctions-for) –

+0

Я отредактировал свое сообщение, чтобы уточнить, что 'Something', который я группирую, является' varchar' в SQL. И мне очень жаль, но я не знаю ответа на вопрос, на который вы ссылаетесь. –

+1

Я бы сказал, что когда group by выполняется без toarray, он преобразуется в выражение sql. Когда вы применяете группу toarray, выполняется по свойству объекта. Поэтому, если вы сначала выполнили код и сделали некоторую дополнительную работу, например, обрезную строку, данные можно было сгруппировать больше. Пожалуйста, +1 для моей фантазии. – sam

ответ

1

Я нашел ответ. Ответ пользователя995219 был полезен, но не полное объяснение.

По-видимому, методы LINQ проверяют содержимое того, над чем они работают. В моем случае я использую классы, созданные Entity Framework. Они имеют «Ключи сущностей», которые позволяют инфраструктуре .net различать две строки, имеющие одно и то же содержимое, и два экземпляра одной и той же строки.

В моем случае я использовал сложный вид, а структура .net неправильно указала ключи сущности, а затем удалила строки, потому что считала, что они одинаковы.

Решение для меня состояло в том, чтобы изменить мое представление, чтобы был GUID, который однозначно идентифицирует каждую строку и использует GUID как ключ сущности.

5

Оператор ToArray выполняет запрос, а группа выполняется в памяти с помощью сопоставления равенства строк. Первые два оператора выполняют группу на уровне SQL. Существуют различия: String Comparison differences between .NET and T-SQL?

В частности, относительно сортировки.

Смежные вопросы