2009-06-16 8 views
12

J'ai des problèmes pour lier à la fois un telerik RadGrid et un plain vanilla ASP.NET GridView aux résultats de la requête LINQ to entities suivante. Dans les deux cas, les grilles contiennent le nombre correct de lignes, mais les données provenant uniquement de la première poignée de lignes sont dupliquées dans toutes les autres lignes. J'affecte directement la valeur de retour de ce code à la propriété DataSource sur les grilles.Lignes en double lors de la liaison de données avec LINQ aux entités

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; 
} 

AJOUTÉE: C'est le code ADO.NET plaine alternatif qui fonctionne:

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; 

PLUS:

  1. La requête envoyée à SQL Server par LINQ fonctionne.
  2. L'itération des résultats de la requête LINQ avant leur renvoi entraîne les mêmes duplications.
  3. L'itération des résultats LINQ dans la méthode d'appel, avant la liaison, entraîne les mêmes duplications.

MISE À JOUR: Sur la base des conseils très logique et le montage de Marc Gravel ci-dessous, je trouve que le concepteur EF avait fait une supposition très inculte à une entité clé pour ma classe d'entité, le premier champ dans sa liste de champs, Département, dont il existe seulement environ sept entrées partagées dans tous les autres enregistrements.

C'est en effet la cause de la duplication. Si seulement je pouvais changer ou supprimer la clé d'entité, mais ce concepteur EF avec toute la logique métier d'un Etch-a-Sketch est admirablement engagé à répéter son choix de clé retardé en riant de moi bloqué dehors en suppliant de changer la clé.

+0

Etes-vous sûr de ce que la table ne contient pas de doublons? La requête est correcte. –

+0

@Alexander, oui, j'en suis sûr. Une requête DataTable simple sur la même vue entraîne la liaison correcte des grilles. – ProfK

+0

S'il vous plaît, montrez plus de code. A la fois fonctionnel et problématique. –

Répondre

30

Il me semble que vous avez une clé primaire borked. L'aspect "gestion des identités" de LINQ-to-SQL et EF signifie qu'il est obligé de vous rendre la même instance chaque fois qu'il voit la même valeur de clé primaire pour le même type d'objet.

Par exemple, compte tenu des données:

id  | name  | ... 
-------+------------+------ 
1  | Fred  | ... 
2  | Barney  | ... 
1  | Wilma  | ... 
1  | Betty  | ... 

Puis si elle pense id est un clé primaire lorsque vous parcourez les objets de LINQ, il est forcé pour vous donner « Fred », " Barney "," Fred "," Fred ". Essentiellement, quand il voit id 1 encore, il ne regarde même pas les autres colonnes - il récupère simplement l'instance avec id 1 du cache d'identité - et vous donne la même instance de Fred qu'il vous a donné précédemment. Si ne pense id est une clé primaire, il traitera chaque ligne comme un objet distinct (et donc si elle a la même valeur dans l'un des champs qu'un autre enregistrement - ce n'est pas exactement inhabituel).

Je vous conseille de vérifier que tous les champs que vous avez marqués comme clé primaire (dans votre modèle DBML/EDM) sont vraiment uniques par ligne.Dans le cas ci-dessus, la colonne id ne représente clairement pas un identifiant unique, elle ne convient donc pas comme clé primaire. Il suffit de le marquer comme tel dans le concepteur LINQ-to-SQL/EF.


mise à jour: en particulier, regardez la propriété « Entité clé » pour les différentes propriétés du concepteur - surtout si vous interrogez une vue. Vérifiez que "Entity Key" est uniquement défini sur true pour les colonnes appropriées (c'est-à-dire celles qui rendent la ligne unique). Si ce paramètre est incorrect, définissez-le sur false. Ceci est également visible en tant qu'icône de clé jaune - cela ne devrait apparaître que sur des choses qui sont véritablement des identifiants uniques pour un enregistrement.

+3

+1 pour l'utilisation de borked. Aussi bonne réponse. –

+0

@ Marc, super truc, vous avez identifié le problème le plus précisément. Cependant, vous suggérez simplement de supprimer l'indicateur de clé d'entité de la colonne de problème, mais je ne suis pas autorisé à le faire. – ProfK

+0

Je peux modifier la clé d'entité pour l'ensemble d'entités, mais pas pour la table, de sorte que les mappages soient «bloqués». – ProfK

1

Et si vous encapsulez la requête de lien dans une parenthèse et utilisez l'extension .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(); 
} 
+0

Cela me donne des résultats encore plus étranges, avec des doublons similaires, mais un ensemble différent d'entrées qui correspondent aux mêmes critères. Je bloguerai les différences. – ProfK

0

Une différence entre vos requêtes de travail et brisées est la clause orderby. J'ai trouvé un documented bug dans l'implémentation orderby dans Linq to Entities ... il peut y avoir d'autres. Essayez de supprimer orderby de la requête cassée et voir si vous obtenez toujours des doublons.

Une autre différence est le OU dans la clause where. Essayez d'utiliser uniquement la première partie [où dp.LastName.StartsWith (searchTerm)] et voyez si vous avez toujours des doublons.

0

J'ai fait face au même problème et l'ai résolu avec une solution de contournement. Je l'affiche ici, car cela pourrait aider les autres à venir ici.

au lieu de sélection dp, utilisez

select new <ObjectName> 
{ 
a = v.a 
b = v.b 
}. 

Cela ne reviendra pas en double.

Questions connexes