为什么我在这个linq查询中遇到编译时错误?

时间:2013-12-03 14:37:02

标签: c# linq entity-framework

编译下面的代码时出现编译时错误,我看不出原因:

关系是多对多的关系

 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

2 个答案:

答案 0 :(得分:4)

第二次致电.SelectMany(x => x.Contacts)时,您目前正在使用ContactDetails的集合。您可以在其上使用SelectMany是值得怀疑的。您需要使用Select代替。

当您想要选择多个项目集合并将它们放入一个SelectMany时,会使用

IEnumerableSelect用于各个字段。由于您正在使用ContactDetail类型的对象(我假设只能有一个联系人),您需要使用Select

编辑:这就是你一步一步地做的事情:

groups_to_querry.SelectMany(x => x.Contacts):从我要查询的所有群组中选择所有联系人。每个群组都有很多联系人,因此请将它们全部放入IEnumerable

类型的Contact个集合中

.Where(x => x.ID == Guid.Empty):...但仅限具有空ID的联系人

.SelectMany(p => p.ContactDetails):然后选择所有这些联系人的许多ContactDetails。每个联系人都有许多ContactDetails,因此将它们全部放入IEnumerable类型的ContactDetail个集合中

.Where(x => x.ID == Guid.Empty):...但只有那些ID为空的ContactDetails

.SelectMany(x => x.Contacts);:现在选择每个ContactDetails的多个联系人。但是,由于编译器知道Contacts和ContactDetails之间存在一对多的关系(而不是相反),该语句是不可能的,因此显示编译错误

答案 1 :(得分:1)

我将您的预期查询解释为“来自多个联系人群组,选择ID = Guid.Empty的所有联系人,并且还包含所有ID = Guid.Empty的详细信息”。

您的代码实际解释的方式是“来自所有拥有Guid.Empty的联系人,选择所有具有Guid.Empty的详细信息,并从这些详细信息中选择所有联系人”。第一个问题是你最终会从细节中选择。这意味着最终的SelectMany应该是Select,因为x.Contacts在这里指的是从详细信息到联系人的多对一关系。

第二个问题是结果将包含重复的联系人,因为每个细节都包含相同的联系人。您应该做的是直接根据其详细信息集过滤联系人,如下所示:

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

请注意,这也会选择零详细信息的联系人,这与查询的行为不同,因此我不确定这是否是您想要的。如果没有,您可以为ContactDetails.Any()添加另一个过滤器。

编辑:由于您使用的是Entity Framework,因此上述内容可能无效。您可能需要在子查询中选择详细信息,然后在执行后在内存中进行过滤:

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