如何在linq join(lambda)上添加where子句?

时间:2011-12-16 08:50:32

标签: c# asp.net linq lambda

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

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

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&lt; {c:Contact,cop:ContactOperationalPlace}&gt;,并且无法转换为联系人...

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

4 个答案:

答案 0 :(得分:12)

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

答案 1 :(得分:1)

您无需在结果选择器功能中返回新对象。委托提供两个变量,以便您可以选择其中一个或其他变体(这将需要一个新对象)。试试这个:

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

答案 2 :(得分:0)

你可以把它转换成var并尝试使用intellisense吗?

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

只是一个想法

答案 3 :(得分:0)

我认为如果你将它作为2个不同的查询开始,然后将它们组合起来会容易得多。我假设关系是Contact(1&lt; - &gt; many)Contactoperationplaces?最后,您将在每个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);

如果您正在使用Entity Framework,只要您定义了表之间的关联,就不必进行任何连接。

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

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