Pourquoi est-ce que je reçois une erreur de temps de compilation dans cette requête LINQ?

StackOverflow https://stackoverflow.com/questions/20354027

  •  25-08-2022
  •  | 
  •  

Question

Je reçois une erreur de temps de compilation lors de la compilation du code ci-dessous et je ne vois pas pourquoi:

Les relations sont nombreuses à de nombreuses relations

 var contacts = groups_to_querry
                .SelectMany(x => x.Contacts)
                .Where(x => x.ID == Guid.Empty)
                .SelectMany(p => p.ContactDetails)
                .Where(x => x.ID == Guid.Empty)
                .SelectMany(x => x.Contacts);  //This line gives me a compile time error 
                //Error : The Type argumetns for method 'System.Linq.Enumerable.SelectMany<TSource,Tresult>
                //(System.Collections.Generic.IEnumerable<TSource>, System.Func<TSource,
                //System.Collections.Generic.IEnumerable<TResult>>)' cannot be infrred from the usage.  
                //Try specifying the type arguments explicitly
Était-ce utile?

La solution

La deuxième fois que vous appelez .SelectMany(x => x.Contacts), vous travaillez actuellement avec une collection de ContactDetails. Il est douteux que vous puissiez utiliser SelectMany dessus. Vous auriez besoin d'utiliser Select Au lieu.

SelectMany est utilisé lorsque vous souhaitez sélectionner plusieurs collections d'articles et les mettre dans une IEnumerable. Select est utilisé sur des champs individuels. Puisque vous travaillez avec des objets de type ContactDetail (ce que je suppose ne peut avoir qu'un seul contact), vous auriez besoin d'utiliser Select

Edit: Voici ce que vous faites en un mot, étape par étape:

groups_to_querry.SelectMany(x => x.Contacts): Depuis tous les groupes que je souhaite interroger, sélectionnez tous leurs nombreux contacts. Chaque groupe a de nombreux contacts, alors mettez-les tous en un seul IEnumerable Collection de type Contact

.Where(x => x.ID == Guid.Empty): ... mais seulement ces contacts avec un identifiant vide

.SelectMany(p => p.ContactDetails): Sélectionnez ensuite tous ces nombreux contacts ContactDetails. Chaque contact a de nombreux contacts, alors mettez-les tous en un seul IEnumerable Collection de type ContactDetail

.Where(x => x.ID == Guid.Empty): ... mais seulement ces contacts avec un identifiant vide

.SelectMany(x => x.Contacts);: Sélectionnez maintenant chacun des nombreux contacts des ContactDetails. Cependant, puisque le compilateur sait qu'il existe une relation un-à-plusieurs entre les contacts et les contacts (et non l'inverse), cette déclaration n'est pas possible, et montre ainsi une erreur de compilation

Autres conseils

J'interprète votre requête prévue comme "à partir de plusieurs groupes de contacts, sélectionnez tous les contacts qui ont id = guid.empty et ont également des détails qui ont tous id = guid.empty".

La façon dont votre code est réellement interprété est "à partir de tous les contacts qui ont Guid.Empty, sélectionnez tous les détails qui ont Guid.Empty, et à partir de ces détails, sélectionnez tous les contacts". Le premier problème est que vous finissez par sélectionner dans les détails. Cela signifie la finale SelectMany devrait être un Select, car x.Contacts Ici, fait référence à la relation plusieurs à un des détails aux contacts.

Le deuxième problème est que le résultat contiendra des doublons des contacts, car le même contact est inclus pour chaque détail. Ce que vous devriez faire à la place, c'est filtrer directement les contacts en fonction de leurs collections de détails, comme ceci:

groups_to_query
.SelectMany(g => g.Contacts)
.Where(c => c.ID == Guid.Empty)
.Where(c => c.ContactDetails.All(d => d.ID == Guid.Empty))

Remarque Cela sélectionnerait également des contacts qui n'ont aucun détail, ce qui est un comportement différent de votre requête, donc je ne sais pas si c'est ce que vous voulez. Vous pouvez ajouter un autre filtre pour ContactDetails.Any() sinon.

Éditer: Puisque vous utilisez Entity Framework, ce qui précède ne fonctionnera probablement pas. Vous devrez peut-être sélectionner les détails dans une sous-requête, puis filtrer en mémoire après son exécution:

var queryResult =
    groups_to_query
    .SelectMany(g => g.Contacts)
    .Where(c => c.ID == Guid.Empty)
    .Select(c => new {
        contact = c,
        detailIDs = c.ContactDetails.Select(d => d.ID)
    }).ToList();

var contacts =
    queryResult
    .Where(r => r.detailIDs.All(id => id == Guid.Empty))
    .Select(r => r.contact);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top