How to add a where clause on a linq join (lambda)?

26,198

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);
Share:
26,198
linnkb
Author by

linnkb

Full time developer

Updated on December 16, 2020

Comments

  • linnkb
    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
    Alexey F over 12 years
    and probably add Distinct() for contact
  • linnkb
    linnkb over 12 years
    I'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
    linnkb over 12 years
    Thank u so much! I knew that the solution would be pretty simple once I found it.
  • linnkb
    linnkb over 12 years
    I 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
    Flater over 12 years
    are 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...