0
votes

Comparaison personnalisée pour la méthode de groupeby dans une requête

Je veux mettre des objets avec des valeurs spécifiques (dans ce cas (int?) null code>) dans différents groupes.

Donc, donc: P>

    private class NullNotEqualComparer : IEqualityComparer<int?>
    {
        public bool Equals(int? x, int? y)
        {
            if (x == null || y == null)
            {
                return false;
            }

            return x.Value == y.Value;
        }

        public int GetHashCode(int? obj)
        {
            return obj.GetHashCode();
        }
    }


0 commentaires

3 Réponses :


1
votes
  1. selon MSDN https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/ef/language-reference/supported-and-unsupported-Linq -Methods-linq-to-entités , Linq-to-entités Groupby ne prend pas en charge le comparateur. P> li>

  2. En fonction de votre exigence, vous pouvez essayer 2 fonctions. Premier bloc filtre toutes les touches NULL, puis le deuxième groupe de blocs par touches non nulles. Comme ça p>

     var nullKeyList = db.Table.Where(x => x.NullableInt == null).ToList();
    
     var valueKeyGroup = db.Table.Where(x => x.NullableInt != null)
                        .GroupBy(t => t.NullableInt).ToList();
    

0 commentaires

1
votes

Hélas, vous avez oublié d'écrire exactement les exigences de vos groupes. Je ne peux pas le déduire de votre comparateur, car le comparateur n'est pas correct.

Selon votre comparateur, si x est égal à NULL, puis x ne correspond pas x p> xxx pré>

Par conséquent, X ne serait pas dans le même groupe que x. P>

Parlons plus tard du comparateur, expliquons d'abord l'exception. P>

IQuiserable ne peut pas utiliser IéquityComParer h2 >

Un iquéryable <...> code> a une expression code> code> et un fournisseur code>. L'expression représente dans une forme générique la requête qui doit être exécutée; Le fournisseur sait quel processus exécutera la requête (généralement un système de gestion de base de données) et quelle langue est utilisée pour communiquer avec ce processus (généralement SQL). P>

tant que vous concatéez des instructions LINQ qui renvoient IQuéryable <...> code>, seul l'expression code> est modifiée. La base de données n'est pas contactée, la requête n'est pas exécutée. Seulement lorsque vous commencez à énumérer en appelant getenumerator () code> (directement ou en profondeur dans une autre fonction, comme Tolist () code> ou foreach code> ), l'expression est envoyée au fournisseur qui essaiera de traduire l'expression en SQL et d'exécuter la requête. Les données renvoyées sont présentées sous la forme d'un ienumerator <...> code>, que vous pouvez utiliser pour accéder aux éléments retournés un par un. P>

Le problème est que le fournisseur ne fait pas Connaissez votre Nullnotequalcomparer code>, et ne peut donc pas le traduire en SQL. En fait, plusieurs méthodes LINQ ne sont pas étayées par Linq-to-entités. Voir [Méthodes supportées et non prises en charge (Linq aux entités)] 1 p>

Vous devrez donc essayer de mettre la comparaison dans le clavier du groupeby. P>

Intermezzo: votre Nullnotequalcomparer h2>

Votre comparateur d'égalité n'est pas un bon comparateur. Il ne répond pas à l'exigence selon laquelle x est égal à x: p> xxx pré>

Qu'attendez-vous et quels sont les résultats? P>

presque toujours, une égalité appropriée Le comparateur commence par les mêmes quatre lignes: p> xxx pré>

dans de rares occasions que vous voulez différents types d'objets égaux. Dans ce cas, vous ne vérifierez pas le type sur. P>

gethascode strong> est utilisé pour vérifier rapidement que deux objets sont différents. Si vous devez comparer l'égalité de mille objets, vous pouvez facilement découvrir que 990 d'entre eux sont différents, que vous ne devez vérifier que complètement les 10 derniers éléments. P>

Pensez à une classe avec 20 propriétés . Pour une égalité totale, vous devez vérifier les 20 propriétés. Si vous choisissez votre sage gethashcode, il peut ne pas être nécessaire de vérifier les 20 propriétés. P>

Par exemple, si vous souhaitez trouver toutes les personnes vivant sur la même adresse, vous devrez vérifier le pays, la ville , Post-code, rue, spouse, ... p>

Un moyen rapide d'éliminer la plupart des personnes de votre séquence d'intrants, seriez-vous de vérifier le code postal uniquement: si deux personnes ont un code postal différent, ils ne vivront pas Sur la même adresse. p>

Par conséquent, la seule exigence de votre gethascode serait: si est égal (x, y) code>, alors gethascode (x) == gethascode (x) = y) code>. Mind You: Pas l'inverse: il peut y avoir des x et y différents, qui ont le même hashcode. Ceci est facile à voir: GetHashCode retourne un int32, il doit donc y avoir plusieurs objets INT64 qui partagent leur hashcode. P> xxx pré>

retour à votre question h2>

IT Il me semble que vous avez créé ce comparateur d'égalité, car vous voulez un groupe séparé pour tous les éléments de votre table qui ont une valeur pour T.NullAllableint égale à NULL. P>

IQueryable<MyClass> tableRows = db.Table.ToMyClass();
var result = tableRows.GroupBy(row => row.NullableInt);
  • Clé 1, Éléments avec ID A, C, F LI>
  • Key 2, élément avec id b li>
  • clé null, éléments avec id d, e, g li> ul>

    Si c'est ce que vous voulez, vous pouvez utiliser le Comparateur par défaut pour la classe NULLLABLE CODE> : P>

    • Hasvalue des X et Y sont faux: retour vrai li>
    • Hasvalue des X et Y sont VRAI: Retour X.Value == Y.Value Li>
    • Dans tous les autres cas: renvoyer false. Li> ul>

      En supposant que vous avez une méthode pour traduire les lignes de votre dt.table sur un iQuiserable: p> xxx pré> p>


1 commentaires

Merci pour une réponse en profondeur. Je suppose que j'aurais peut-être maudit ma question de manière incorrecte mais dans la première ligne, j'écris je veux mettre des objets avec des valeurs spécifiques (dans ce cas (int?) Null) dans différents groupes. Par ceci, je veux dire que Je veux des entités avec la valeur null pour finir par différents groupes.



0
votes

En fin de compte, je suis allé avec un peu de hack, mais c'est assez simple et fonctionne bien. Je pensais que je l'écrirais ici car cela pourrait être utile pour les autres.

Dans ma question, le nullableint est en fait un identifiant à une table différente et je sais donc qu'il sera toujours supérieur à zéro .

Pour cette raison, je peux faire quelque chose comme ceci: xxx


0 commentaires