Дублировать строки при привязке данных с LINQ к объектам
У меня есть проблемы, связывающие как telerik RadGrid, так и простой ванильный ASP.NET GridView с результатами следующего запроса LINQ к объектам. В обоих случаях сетки содержат правильное количество строк, но данные только из первой части строк дублируются во всех остальных строках. Я прямо присваиваю возвращаемое значение из этого кода свойство DataSource на сетках.
public IEnumerable<DirectoryPersonEntry> FindPersons(string searchTerm)
{
DirectoryEntities dents = new DirectoryEntities();
return from dp in dents.DirectoryPersonEntrySet
where dp.LastName.StartsWith(searchTerm) || dp.Extension.StartsWith(searchTerm)
orderby dp.LastName, dp.Extension
select dp;
}
ADDED: Это альтернативный простой ADO.NET-код, который работает:
DataTable ret = new DataTable();
using (SqlConnection sqn = new SqlConnection(ConfigurationManager.ConnectionStrings["WaveAdo"].ConnectionString))
{
SqlDataAdapter adap = new SqlDataAdapter("select * from DirectoryPersonList where LastName like '" + searchTerm + "%' order by LastName ", sqn);
sqn.Open();
adap.Fill(ret);
}
return ret;
БОЛЬШЕ:
- Выполняется запрос, отправленный в SQL Server по LINQ.
- Итерация результатов запроса LINQ перед возвратом результатов приводит к тем же дублированиям.
- Итерация результатов LINQ в вызывающем методе перед привязкой приводит к тем же дублированиям.
UPDATE:
Основываясь на очень логичном и подходящем совете от Марка Гравеля ниже, я обнаружил, что дизайнер EF сделал очень необразованную догадки в Entity Key для моего класса сущности, первого поля в его списке полей, Department, из которых есть только около семи записей, общих для всех других записей.
Это действительно причина дублирования. Если бы я мог изменить или удалить ключ сущности, но этот дизайнер EF со всей бизнес-логикой Etch-a-Sketch превосходно привержен повторению этого замедленного выбора ключа, а смех над мной заперт вне прошения, чтобы изменить ключ.
Ответы
Ответ 1
Мне кажется, что у вас есть первичный ключ borked. Аспект "управления идентификацией" LINQ to SQL и EF означает, что он обязан вернуть вам тот же самый экземпляр всякий раз, когда он видит одно и то же значение первичного ключа для одного и того же типа объекта.
Например, учитывая данные:
id | name | ...
-------+------------+------
1 | Fred | ...
2 | Barney | ...
1 | Wilma | ...
1 | Betty | ...
Затем , если он считает, что id
является первичным ключом при повторении объектов из LINQ, он вынужден дать вам "Fred" , "Barney", "Fred" , "Fred" , По сути, когда он снова видит id
1, он даже не смотрит на другие столбцы - он просто извлекает экземпляр с помощью id
1 из кеша идентификации и дает вам тот же экземпляр Fred, который он дал вам ранее. Если он не считает, что id
является первичным ключом, он будет рассматривать каждую строку как отдельный объект (и, следовательно, что, если он имеет одно и то же значение в одном из полей в качестве другой записи, что не совсем необычно).
Я бы посоветовал проверить, что любые поля, отмеченные как первичный ключ (в вашей модели DBML/EDM), действительно уникальны для каждой строки. В приведенном выше случае столбец id
явно не представляет собой уникальный идентификатор, поэтому он не подходит в качестве первичного ключа. Просто отмените его как таковой в дизайнере LINQ-to-SQL/EF.
update: в частности, посмотрите на свойство "Entity Key" для различных свойств в дизайнере - особенно если вы запрашиваете представление. Убедитесь, что для "подходящих столбцов" используется значение "Ключ сущности", т.е. Те, которые делают строку уникальной). Если он установлен неправильно, установите для него значение false. Это также видно как значок желтого ключа - это должно появляться только в тех вещах, которые действительно являются уникальными идентификаторами для записи.
Ответ 2
И если вы завершите запрос ссылки в скобках и используете расширение .Distinct()?
public IEnumerable<DirectoryPersonEntry> FindPersons(string searchTerm)
{
DirectoryEntities dents = new DirectoryEntities();
return (from dp in dents.DirectoryPersonEntrySet
where dp.LastName.StartsWith(searchTerm) || dp.Extension.StartsWith(searchTerm)
orderby dp.LastName, dp.Extension
select dp).Distinct();
}
Ответ 3
Одно из различий между вашими рабочими и сломанными запросами - это предложение orderby. Я нашел документированную ошибку в реализации orderby в Linq для Entities... могут быть и другие.
Попробуйте удалить orderby из сломанного запроса и посмотрите, есть ли у вас дубликаты.
Другим отличием является OR в предложении where. Попробуйте использовать только первую часть [где dp.LastName.StartsWith(searchTerm)] и посмотреть, есть ли у вас дубликаты.
Ответ 4
Я столкнулся с той же проблемой и решил ее обходным путем. Я размещаю его здесь, так как это может помочь другим приходить сюда.
вместо выбора dp, используйте
select new <ObjectName>
{
a = v.a
b = v.b
}.
Это не будет возвращать дубликаты.