Comment mettre en œuvre IEqualityComparer pour retourner des valeurs distinctes?
J'ai un L2E requête qui renvoie des données qui contient des objets en double. J'ai besoin de supprimer ces objets en double. En gros je doit supposer que si leurs noms sont les mêmes, les objets sont en double. J'ai essayé q.Distinct()
, mais qui toujours retourné à dupliquer des objets. Alors j'ai essayé de mettre mon propre IEqualityComparer et en passant à la Distinct()
méthode. La méthode a échoué avec le texte suivant:
LINQ to entities ne reconnaît pas la méthode
'Système.Linq.IQueryable1[DAL.MyDOClass]
1[DAL.MyDOClass],
Distinct[MyDOClass](System.Linq.IQueryable
Système.Les Collections.Génériques.IEqualityComparer`1[DAL.MyDOClass])'
méthode, et cette méthode ne peut pas être traduit dans un magasin d'expression.
Et ici est la mise en œuvre de EqualityComparer:
internal class MyDOClassComparer: EqualityComparer<MyDOClass>
{
public override bool Equals(MyDOClass x, MyDOClass y)
{
return x.Id == y.Id;
}
public override int GetHashCode(MyDOClass obj)
{
return obj == null ? 0 : obj.Id;
}
}
Alors, comment dois-je écrire mon propre IEqualityComparer
correctement?
Vous devez vous connecter pour publier un commentaire.
Un
EqualityComparer
est pas la voie à suivre - il ne peut filtrer vos résultats dans la mémoire par exemple:Vous pouvez utiliser le
GroupBy
méthode de groupe par l'IDs et lesFirst
méthode pour permettre à votre base de données de récupérer uniquement une entrée unique par ID, par exemple:IQueryable.First
méthode - mais il prend en charge laIQueryable.FirstOrDefault
méthode. Dans ce cas, comme vous le dites, logiquement, aurait les mêmes résultats (mais seulement l'une des deux méthodes sont mises en œuvre dans le fournisseur).asQueryable().GroupBy(o => o.Id).Select(c => c.FirstOrDefault())
riche.okelly et Ladislav Mrnka sont tous les deux corrects de différentes manières.
À la fois leurs réponses composer avec le fait que la
IEqualityComparer<T>
's méthodes de ne pas être traduite en SQL.Je pense qu'il est utile de regarder les avantages et les inconvénients de chacun, qui va prendre un peu plus d'un commentaire.
riches approche de la ré-écrit la requête pour une requête différente avec le même résultat final. Leur code devrait aboutir à plus ou moins comment vous pouvez vous efficacement, le faire avec la main codé SQL.
Ladislav de la il sort de la base de données au point avant de l'distinctes, et alors en mémoire une approche de travail.
Depuis la base de données est grand à faire le tri, de regroupement et de filtrage rich dépend, il est susceptible d'être le plus performant dans ce cas. Vous pourriez bien trouver que la complexité de ce qui se passe avant ce regroupement est telle que Linq-to-entités n'est pas bien de générer une requête unique, mais plutôt produit un ensemble de requêtes et fait partie du travail de mémoire, ce qui pourrait être assez méchant.
Généralement le regroupement est plus cher que distinctes en mémoire des cas (surtout si vous la mettre en mémoire avec
AsList()
plutôt queAsEnumerable()
). Donc, si vous étiez déjà en cours afin de la mettre en mémoire, à ce stade, en raison d'une autre exigence, il serait plus performant.Il serait aussi le seul choix si votre définition de l'égalité est quelque chose qui ne se rapportent pas bien à ce qui est disponible dans la base de données, et bien sûr, il vous permet de passer de l'égalité des définitions si vous voulais le faire sur un
IEqualityComparer<T>
passé en paramètre.Dans tous, rich est la réponse que je dirais serait plus susceptible d'être le meilleur choix ici, mais les différents avantages et les inconvénients de Ladislav par rapport à rich rend également bien la peine de les étudier et de les considérer.
Vous ne serez pas.
Distinct
opérateur est appelé sur la base de données de sorte que tout code que vous écrivez dans votre application ne peut pas être utilisé (vous ne pouvez pas déplacer vos égalité comparateur logique de SQL), sauf si vous êtes heureux avec le chargement de tous les non-valeurs distinctes et de les rendre distinctes de filtrage dans votre application.ToList()
plutôt queToEnumerable()
?ToEnumerable
serait suffisant.Réponse tardive mais vous pouvez faire mieux:
si le DAL objet est partielle (généralement est de savoir si c'est une base de données objet), vous pouvez l'étendre comme ceci:
Et distinctes fonctionnera sans aucune surcharge en elle.
Si pas, vous pouvez créer la classe IEqualityComparer comme ceci:
Et encore une fois, utilisez l'Distinctes sans aucune surcharge
GroupBy()
peut être une meilleure solution queDistinct()
- comme mentionné dans le top rated répondre sur cette question.