How to add a where clause on a linq join (lambda)?
Solution 1
You create an anonymous type with both objects before your where clause and filter it on ContactOperationPlaces value. You just have to select the Contact after that.
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();
Solution 2
You don't need to return new objects in the result selector function. The delegate provides both variables so you can choose one or the other, or some other variation (which would require a new object). Try this:
query.Join(_ctx.ContactOperationPlaces, c => c.Id, cop => cop.ContactId,
(c, cop) => c).Where(o => o.cop.municipalityId == 301);
Comments
-
linnkb over 3 years
I have two database tables Contact (Id, Name, ...) and ContactOperationalPlaces (ContactId, MunicipalityId), where a contact can be connected to several ContactOperationalPlaces.
What I'm trying to do is to build a query (ASP .NET, C#) with IQueryable, that only selects all the contacts that exists in the ContactOperationalPlaces table, with a given MunicipalityId.
The sql query looks like this:
select * from Contacts c right join ContactOperationPlaces cop on c.Id = cop.ContactId where cop.MunicipalityId = 301;
With linq it would look something like this:
//_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);
So, I know how to do this if the point was to select all of this at once, unfortunately it's not. I'm building a query based on user input, so I don't know all of the selection at once.
So this is what my code looks like:
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 ...........?);
The difference with the two where statements is that with the first one, each contact has only one name, but with the latter a contact can contain several operational places...
I have managed to find one solution, but this solution gives me an unidentyfied object, that contains both of the tables. And I don't know how to proceed with it.
query.Join(_ctx.ContactOperationPlaces, c => c.Id, cop => cop.ContactId, (c, cop) => new {c, cop}).Where(o => o.cop.municipalityId == 301);
The object returned from this expression is System.Linq.Iqueryable<{c:Contact, cop:ContactOperationalPlace}>, and it can't be cast to Contacts...
So, that's the issue. The answer is probably pretty simple, but I just can't find it...
-
Alexey F over 12 yearsand probably add Distinct() for contact
-
linnkb over 12 yearsI've tried this before, and since i don't do like this: (c, cop) => new {c, cop}, I won't get the opportunity to select cop in the where clause...
-
linnkb over 12 yearsThank u so much! I knew that the solution would be pretty simple once I found it.
-
linnkb over 12 yearsI want to keep the contact that has a connection to a specific municipationId in contactoperationalplaces, so i want one item per contact. I know the latter solution is the best, but as I explained in my question, I can't select all at once.
-
Flater over 12 yearsare these different tables connected throug a one-to-many association? If so, this is your best solution. If you have other joins on which contact relies, you should replaces those by doing something similar like the above. As EF does all the joining for you and you have to only say what you want, I think manually joining tables against EF is inefficient by default (except for some very, very unusual situations perhaps). Not blaming you, but I'd suggest steering clear from doing manual joins as you will have to do more work, with less feedback/debugging...