如何在linq连接(lambda)上添加where子句
本文关键字:添加 where 子句 lambda linq 连接 | 更新日期: 2023-09-27 18:17:57
我有两个数据库表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语句的不同之处在于,第一个where语句中,每个联系人只有一个名字,而后一个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<{c:Contact, cop:ContactOperationalPlace}>,它不能被强制转换为Contacts…
这就是问题所在。答案可能很简单,但我就是找不到……
在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();
不需要在结果选择器函数中返回新对象。委托提供了两个变量,因此您可以选择其中一个或另一个,或者其他一些变体(这将需要一个新的对象)。试试这个:
query.Join(_ctx.ContactOperationPlaces, c => c.Id, cop => cop.ContactId,
(c, cop) => c).Where(o => o.cop.municipalityId == 301);
你能把它转换为var并尝试使用智能感知吗?
var myCast = query.Join(_ctx.ContactOperationPlaces, c => c.Id, cop => cop.ContactId,
(c, cop) => new {c, cop}).Where(o => o.cop.municipalityId == 301);
只是一个想法
我认为这将是容易得多,如果你开始作为2个不同的查询,然后结合它们。我假设关系是Contact (1 <-> many) Contactoperationplaces ?最后,您将为每个Contactoperationplaces显示1个条目,而不是每个Contact显示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);
如果你使用实体框架,你不需要做任何连接,只要你定义表之间的关联。
现在我看到了它,我的第二个解决方案更有效,更容易。但是如果你需要在这些命令之间做一些其他的处理,解决方案一也可以工作:)
如果你需要更多的解释,请随时提问:)