I wanted to create an extension method to enable left outer joins in linq/lambda IQueryables, and I have come up with the following, but I am still not sure it's completely correct.
public static IQueryable<TResult> LeftOuterJoin<TOuter, TInner, TKey, TResult>(
this IQueryable<TOuter> outer,
IQueryable<TInner> inner,
Expression<Func<TOuter, TKey>> outerKeySelector,
Expression<Func<TInner, TKey>> innerKeySelector,
Func<TOuter, TInner, TResult> resultSelector)
{
return outer.GroupJoin(
inner,
outerKeySelector,
innerKeySelector,
(o, i) => new { outer = o, innerCollection = i })
.SelectMany(
a => a.innerCollection.DefaultIfEmpty(),
(a, i)=>resultSelector(a.outer,i));
}
I am especially concerned with the resultSelector
being a Func
, not an Expression
, but I cant call an Expression
in the lambda on the last line. I assume it gets cast automatically, but it's only an assumption.
Is this correct? How can I improve this? Can it be optimized more?
-
\$\begingroup\$ Have tested it? Does it generate a left outer join sql? \$\endgroup\$t3chb0t– t3chb0t2017年01月13日 13:33:05 +00:00Commented Jan 13, 2017 at 13:33
-
\$\begingroup\$ I've tested it on AsQueriable collections, unfortunately haven't yet had the opportunity to test it on an actual database \$\endgroup\$Kravaros– Kravaros2017年01月17日 12:16:03 +00:00Commented Jan 17, 2017 at 12:16
-
1\$\begingroup\$ If you didn't actually test it, how would you know if the improvements are improvements at all? \$\endgroup\$t3chb0t– t3chb0t2017年01月17日 12:25:25 +00:00Commented Jan 17, 2017 at 12:25
1 Answer 1
Actually, it is way more complex than that, since Funcs<> cant't be translated to the database, so you'll have to "call" the expression. But since you can't call a expression, you'll have to change the expression into another that means what you need it to means.
Check out this question on StackOverflow. It has an good explanation on Linq inner workings and the accepted answer has a method that do the outer join. Be sure to read the second answer too, since it shows some issues that arise on more complex queries. And just as a warning, the method you are trying to write will easily gets 150 lines long (that's why I didn't copied it here)...
-
\$\begingroup\$ Thank you for your answer, this is exactly what i was worried about. I will do some more reading on your link. \$\endgroup\$Kravaros– Kravaros2017年01月17日 12:17:12 +00:00Commented Jan 17, 2017 at 12:17