LINQ Joining in C# with multiple conditions

C#LinqJoinMultiple Conditions

C# Problem Overview


I have a LINQ Joining statement in C# with multiple conditions.

var possibleSegments = 
    from epl in eventPotentialLegs
    join sd in segmentDurations on 
        new { 
            epl.ITARequestID, 
            epl.ITASliceNumber, 
            epl.DepartAirportAfter, 
            epl.AirportId_Origin, 
            epl.AirportId_Destination 
        } 
        equals 
        new { 
            sd.ITARequestId, 
            sd.SliceIndex, 
            sd.OriginAirport, 
            sd.DestinationAirport 
        }
    where
        epl.DepartAirportAfter > sd.UTCDepartureTime 
        and 
        epl.ArriveAirportBy > sd.UTCArrivalTime
    select new PossibleSegments{ ArrivalTime = sd.arrivalTime };

The joining does not work correctly. What am I doing wrong?

C# Solutions


Solution 1 - C#

As far as I know you can only join this way:

var query = from obj_i in set1
join obj_j in set2 on 
    new { 
      JoinProperty1 = obj_i.SomeField1,
      JoinProperty2 = obj_i.SomeField2,
      JoinProperty3 = obj_i.SomeField3,
      JoinProperty4 = obj_i.SomeField4
    } 
    equals 
    new { 
      JoinProperty1 = obj_j.SomeOtherField1,
      JoinProperty2 = obj_j.SomeOtherField2,
      JoinProperty3 = obj_j.SomeOtherField3,
      JoinProperty4 = obj_j.SomeOtherField4
    }

The main requirements are: Property names, types and order in the anonymous objects you're joining on must match.

You CAN'T use ANDs, ORs, etc. in joins. Just object1 equals object2.

More advanced stuff in this LinqPad example:

class c1 
	{
	public int someIntField;
	public string someStringField;
	}
	
class c2 
	{
	public Int64 someInt64Property {get;set;}
	private object someField;
	public string someStringFunction(){return someField.ToString();}
	}
	
void Main()
{
	var set1 = new List<c1>();
	var set2 = new List<c2>();
	
	var query = from obj_i in set1
	join obj_j in set2 on 
		new { 
				JoinProperty1 = (Int64) obj_i.someIntField,
				JoinProperty2 = obj_i.someStringField
			} 
		equals 
		new { 
				JoinProperty1 = obj_j.someInt64Property,
				JoinProperty2 = obj_j.someStringFunction()
			}
	select new {obj1 = obj_i, obj2 = obj_j};
}

Addressing names and property order is straightforward, addressing types can be achieved via casting/converting/parsing/calling methods etc. This might not always work with LINQ to EF or SQL or NHibernate, most method calls definitely won't work and will fail at run-time, so YMMV (Your Mileage May Vary). This is because they are copied to public read-only properties in the anonymous objects, so as long as your expression produces values of correct type the join property - you should be fine.

Solution 2 - C#

Your and should be a && in the where clause.

where epl.DepartAirportAfter >  sd.UTCDepartureTime 
and epl.ArriveAirportBy > sd.UTCArrivalTime

should be

where epl.DepartAirportAfter >  sd.UTCDepartureTime 
&& epl.ArriveAirportBy > sd.UTCArrivalTime

Solution 3 - C#

If you need not equal object condition use cross join sequences:

var query = from obj1 in set1
from obj2 in set2
where obj1.key1 == obj2.key2 && obj1.key3.contains(obj2.key5) [...conditions...]

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRatheeshView Question on Stackoverflow
Solution 1 - C#Zar ShardanView Answer on Stackoverflow
Solution 2 - C#p.campbellView Answer on Stackoverflow
Solution 3 - C#QioView Answer on Stackoverflow