Question

I am getting a compile time error when compiling the below code and I can't see why:

Relations are many to many 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
Was it helpful?

Solution

The second time you call for .SelectMany(x => x.Contacts), you are currently working with a collection of ContactDetails. It is doubtful that you would be able to use SelectMany on it. You would need to use Select instead.

SelectMany is used when you want to select multiple collections of items and put them into one IEnumerable. Select is used on individual fields. Since you are working with objects of type ContactDetail (which I assume can only have one contact), you would need use Select

EDIT: Here is what you're doing in a nutshell, step by step:

groups_to_querry.SelectMany(x => x.Contacts): From all the groups that I want to query select all of their many contacts. Each group has many contacts, so put them all into a single IEnumerable collection of type Contact

.Where(x => x.ID == Guid.Empty): ...but only those Contacts with an empty ID

.SelectMany(p => p.ContactDetails): Then select all of those Contacts' many ContactDetails. Each Contact has many ContactDetails, so put them all into a single IEnumerable collection of type ContactDetail

.Where(x => x.ID == Guid.Empty): ...but only those ContactDetails with an empty ID

.SelectMany(x => x.Contacts);: Now select each of the ContactDetails' many Contacts. However, since the compiler knows that there is a one-to-many relationship between Contacts and ContactDetails (and not the other way around) that statement is not possible, and thus shows a compile error

OTHER TIPS

I'm interpreting your intended query as "from multiple groups of contacts, select all contacts that have ID=Guid.Empty and also have details that all have ID=Guid.Empty".

The way your code is actually interpreted is "from all contacts that have Guid.Empty, select all details that have Guid.Empty, and from those details select all contacts". The first problem is that you end up selecting from details. This means the final SelectMany should be a Select, because x.Contacts here refers to the many-to-one relationship from details to contacts.

The second problem is that the result will contain duplicates of contacts, because the same contact is included for each details. What you should be doing instead is filtering the contacts directly based on their details collections, like this:

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

Note this would also select contacts that have zero details, which is different behavior from your query, so I'm not sure if it's what you want. You could add another filter for ContactDetails.Any() if not.

Edit: Since you're using Entity Framework, the above probably won't work. You may need to select the details in a subquery and then filter in memory after it executes:

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);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top