【问题标题】:How to add a where clause on a linq join (lambda)?如何在 linq 连接(lambda)上添加 where 子句?
【发布时间】:2012-01-21 20:05:23
【问题描述】:

我有两个数据库表 Contact (Id, Name, ...) 和 ContactOperationalPlaces (ContactId, MunicipalityId),其中一个联系人可以连接到多个 ContactOperationalPlaces。

我要做的是使用 IQueryable 构建一个查询(ASP .NET、C#),它只选择存在于 ContactOperationalPlaces 表中的所有联系人,以及给定的 MunicipalityId。

sql 查询如下所示:

select * from Contacts c 
right join ContactOperationPlaces cop on c.Id = cop.ContactId 
where cop.MunicipalityId = 301;

使用 linq 它看起来像这样:

//_ctx is the context
var tmp = (from c in _ctx.Contacts
             join cop in _ctx.ContactOperationPlaces on c.Id equals cop.ContactId
             where cop.MunicipalityId == 301
             select c);

所以,如果要一次选择所有这些,我知道该怎么做,不幸的是它不是。我正在根据用户输入构建查询,所以我不能一次知道所有的选择。

这就是我的代码的样子:

IQueryable<Contacts> query = (from c in _ctx.Contacts select c);
//Some other logic....
/*Gets a partial name (string nameStr), and filters the contacts 
 so that only those with a match on names are selected*/
query = query.Where(c => c.Name.Contains(nameStr);
//Some more logic
//Gets the municipalityId and wants to filter on it! :( how to?
query = query.where(c => c.ContactOperationalPlaces ...........?);

这两个where语句的区别在于,第一个,每个联系人只有一个名字,而后者一个联系人可以包含多个可操作的地方……

我设法找到了一个解决方案,但这个解决方案给了我一个身份不明的对象,其中包含两个表。而且我不知道该怎么做。

query.Join(_ctx.ContactOperationPlaces, c => c.Id, cop => cop.ContactId,
      (c, cop) => new {c, cop}).Where(o => o.cop.municipalityId == 301);

此表达式返回的对象是 System.Linq.Iqueryable,不能强制转换为 Contacts...

所以,这就是问题所在。答案可能很简单,但就是找不到……

【问题讨论】:

    标签: c# asp.net linq lambda


    【解决方案1】:

    您在 where 子句之前使用两个对象创建一个匿名类型,并根据 ContactOperationPlaces 值对其进行过滤。之后您只需选择联系人即可。

    query.Join(_ctx.ContactOperationPlaces, c => c.Id, cop => cop.ContactId,
               (c, cop) => new {c, cop}).Where(o => o.cop.municipalityId == 301)
                                        .Select(o => o.c)
                                        .Distinct();
    

    【讨论】:

    • 并可能添加 Distinct() 联系方式
    • 非常感谢!我知道一旦找到解决方案,它就会非常简单。
    【解决方案2】:

    我认为,如果您将其作为 2 个不同的查询开始,然后将它们组合起来,会容易得多。我假设关系是 Contact (1 many) Contactoperationplaces ?最后,您将显示每个联系人操作地点 1 个项目,而不是每个联系人显示 1 个项目?

    这样做:

    IQueryable<Contacts> query = (from c in _ctx.Contacts select c);
    
    ...
    
    query = query.Where(x=> x.Name.ToLower().Contains(nameStr.ToLower());
    
    ...
    
    IQueryable<ContactOperationPlaces> query_2 =
         (from c in _ctx.ContactOperationPlaces
           where query.Where(x=> x.Name == c.Contact.Name).Count() > 0
           select c);
    
     //Now query_2 contains all contactoperationsplaces which have a contact that was found in var query
    

    相反,有一种更简单的方法可以做到这一点,那就是完全跳过第一部分。

    IQueryable<ContactOperationPlaces> query_2 =
         (from c in _ctx.ContactOperationPlaces
           where c.Contact.Name.ToLower().Contains(strName.ToLower())
           select c);
    

    如果您使用的是实体框架,则无需执行任何连接,只要您定义了表之间的关联即可。

    现在我看了一下,我的第二个解决方案更高效、更容易。但是,如果您需要在这些命令之间进行一些其他处理,解决方案一也可以:)

    如果您需要更多解释,请随时询问:)

    【讨论】:

    • 我想在contactoperationalplaces 中保留与特定municipationId 有联系的联系人,所以我希望每个联系人都有一个项目。我知道后一种解决方案是最好的,但正如我在问题中解释的那样,我不能一次全部选择。
    • 这些不同的表是否通过一对多关联进行连接?如果是这样,这是您最好的解决方案。如果您有联系人所依赖的其他联接,则应通过执行与上述类似的操作来替换这些联接。由于 EF 会为您完成所有连接,而您只需说出您想要的内容,我认为默认情况下,针对 EF 手动连接表效率低下(可能除了一些非常非常不寻常的情况)。不怪你,但我建议不要进行手动连接,因为你将不得不做更多的工作,更少的反馈/调试......
    【解决方案3】:

    您不需要在结果选择器函数中返回新对象。委托提供了这两个变量,因此您可以选择一个或另一个,或其他一些变体(这将需要一个新对象)。试试这个:

    query.Join(_ctx.ContactOperationPlaces, c => c.Id, cop => cop.ContactId,
      (c, cop) => c).Where(o => o.cop.municipalityId == 301);
    

    【讨论】:

    • 我以前试过这个,因为我不这样做:(c, cop) => new {c, cop},我不会有机会选择 cop in where 子句...
    【解决方案4】:

    您可以将其转换为 var 并尝试对其使用智能感知吗?

     var myCast = query.Join(_ctx.ContactOperationPlaces, c => c.Id, cop => cop.ContactId,
      (c, cop) => new {c, cop}).Where(o => o.cop.municipalityId == 301);
    

    只是一个想法

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-04
      • 1970-01-01
      • 1970-01-01
      • 2016-03-22
      • 2021-04-09
      • 2018-01-25
      相关资源
      最近更新 更多