LINQ рдкрд░ Outer Join рдХрд░реЗрдВ

LINQ - C # рдореЗрдВ рдХрд┐рддрдирд╛ рдЖрд╡рд┐рд╖реНрдХрд╛рд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рддрд╛рдХрд┐ рд╣рдо рднрд╛рд╖рд╛ рдПрдХреАрдХреГрдд рдХреНрд╡реЗрд░реА рдХреЗ рдЖрдирдВрдж рдХрд╛ рдЖрдирдВрдж рд▓реЗ рд╕рдХреЗрдВред рдЕрд░реНрдерд╛рддреН:

  • рдЬреЗрдиреЗрд░рд┐рдХреНрд╕
  • рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдХреЗ рддрд░реАрдХреЗ
  • рд▓рдордбрд╛ рднрд╛рд╡
  • рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХреЗ рдкреЗрдбрд╝
  • рдПрдиреЛрдирдорд╕ рдкреНрд░рдХрд╛рд░
  • рдСрдмреНрдЬреЗрдХреНрдЯ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝рд░
  • рдЯрд╛рдЗрдкрд┐рдВрдЧ

рдФрд░ рдпрд╣ рд╕рдм рдЗрддрдирд╛ рд╣реИ рдХрд┐ рд╣рдо рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ:
	var query = 
		from itemA in listA
		join itemB in listB
			on itemA.Key equals itemB.Key
		select new {itemA, itemB};
	

рдХреЛрдИ рдЕрд╕рд╣рдордд рдирд╣реАрдВ рд╣реЛ рд╕рдХрддрд╛ - рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд░рддрд╛ рд╣реИред

рдФрд░ рдЗрд╕ рд╕рднреА рд╕рд┐рдиреНрдереЗрдЯрд┐рдХ рдЪреАрдиреА рдХреЗ рдмреАрдЪ рдореЗрдВ рдУрд╕ рдХрд╛ рдПрдХ рдЪрдореНрдордЪ рдерд╛ рдЬреЛ рдореБрдЭреЗ рдкрд░реНрдпрд╛рдкреНрдд рдиреАрдВрдж рд▓реЗрдиреЗ рд╕реЗ рд░реЛрдХрддрд╛ рдерд╛ :)

рдпрд╣ OUTER JOIN рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди рдХреА рдХреБрд▓ рдХрдореА рд╣реИред рд▓реЗрдХрд┐рди рдЬреИрд╕рд╛ рдХрд┐ рдпрд╣ рдирд┐рдХрд▓рд╛ рдЯрд╛рд░ рдЖрд╕рд╛рдиреА рд╕реЗ рдмрджрд▓ рдЬрд╛рддрд╛ рд╣реИ ... рдореБрдбрд╝рддрд╛ рд╣реИ ... рдореБрдбрд╝рддрд╛ рд╣реИ ...

... рдПрдХ рдФрд░ рд╕рд┐рдпрд╛рдЯрд┐рдХ рд╢рд░реНрдХрд░рд╛ рдореЗрдВред

рдЬрд┐рди рд▓реЛрдЧреЛрдВ рдиреЗ рдЗрдВрдЯрд░рдиреЗрдЯ рдкрд░ LEFT OUTER JOIN рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рдорд╛рдзрд╛рди рдЦреЛрдЬрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХреА, рд╡реЗ рд╢рд╛рдпрдж рдПрдХ рд╕рдорд╛рди рд╕рдорд╛рдзрд╛рди рдЬрд╛рдирддреЗ рд╣реИрдВ:

	var query = 
		from itemA in listA
		join itemB in listB
			on itemA.Key equals itemB.Key into outer
		from itemO in outer.DefaultIfEmpty()
		select new {itemA, itemO};
	

рдРрд╕рд╛ рдбрд┐рдЬрд╝рд╛рдЗрди рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдкрд░рд┐рдорд╛рдг рдХреЗ рдПрдХ рдЖрджреЗрд╢ рд╕реЗ рд╕рдордЭ рдХреЛ рднреНрд░рдорд┐рдд рдХрд░рддрд╛ рд╣реИ рдФрд░ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╕рд░рд▓ рдирд┐рд░реНрдорд╛рдг рдХреЛ рдЬрдЯрд┐рд▓ рдмрдирд╛рддрд╛ рд╣реИред рдФрд░ рдпрд╣ рдЗрдирд╕реНрдЯреНрд░реАрдо рдЬреЙрдЗрди рдХреЗ рд▓рд┐рдП LEFT OUTER JOIN рд╣реИред рдЭрдЯрдХреЗ рдХреЛ рдЬрд╛рд░реА рдирд╣реАрдВ рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВ рдлреБрд▓ рдСрд╡рд░ рдЬреЙрдЗрди рдХреЗ рд╕рд╛рде рдПрдХ рдЙрджрд╛рд╣рд░рдг рдирд╣реАрдВ рджреВрдВрдЧрд╛ред

рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдЬреИрд╕реЗ рдпрд╣ рдЖрд╕рд╛рди рд╣реЛрдЧрд╛ рдЕрдЧрд░ рд╣рдо рдЗрд╕ рддрд░рд╣ рд╕реЗ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ:

	var query = 
		from itemA in listA
		left join itemB in listB
			on itemA.Key equals itemB.Key
		select new {itemA, itemB};
	

рдпрд╛ рдРрд╕рд╛

	var query = 
		from itemA in listA
		full join itemB in listB
			on itemA.Key equals itemB.Key
		select new {itemA, itemB};
	

рд▓реЗрдХрд┐рди рдирд╣реАрдВред C # рдХреЗ рд▓реЗрдЦрдХреЛрдВ рдиреЗ рд╣рдореЗрдВ рдРрд╕рд╛ рдЖрдирдВрдж рдирд╣реАрдВ рджрд┐рдпрд╛ред рдЦреИрд░, рдЗрд╕рд╕реЗ рдХреЛрдИ рдлрд░реНрдХ рдирд╣реАрдВ рдкрдбрд╝рддрд╛ред рдлрд┐рд░ рднреА, рд╡реЗ рд╣рдореЗрдВ рдЕрдкрдиреЗ рджрдо рдкрд░ рдРрд╕рд╛ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдВрдЧреЗ, рд╣рд╛рд▓рд╛рдВрдХрд┐ рдЗрддрдиреЗ рд╕реБрдВрджрд░ рддрд░реАрдХреЗ рд╕реЗ рдирд╣реАрдВред

рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЕрдЧрд░ рдХреЛрдИ рдЖрдкрдХреЛ рдмрддрд╛рддрд╛ рд╣реИ рдХрд┐ LINQ рдФрд░ System.Collections.Generic.IEnumerable рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдореЗрдВ рдХреБрдЫ рд╕рд╛рдорд╛рдиреНрдп рд╣реИ рдФрд░ рдЕрд▓рдЧ рд╕реЗ рдореМрдЬреВрдж рдирд╣реАрдВ рд╣реИ, рддреЛ рдЖрдк рд╕реБрд░рдХреНрд╖рд┐рдд рд░реВрдк рд╕реЗ рд╡реНрдпрдХреНрддрд┐ рдХреЛ рд╣рдБрд╕рд╛ рд╕рдХрддреЗ рд╣реИрдВ ...

рдбрд┐рдЬрд╝рд╛рдЗрди

	var query = 
		from itemA in listA
		join itemB in listB
			on itemA.Key equals itemB.Key
		select new {itemA, itemB};

рдпрд╣ рдХреЗрд╡рд▓ рд╕рдВрдХрд▓рдХ рджреНрд╡рд╛рд░рд╛ рдкрд╛рддреНрд░реЛрдВ рдХреЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЕрдиреБрдХреНрд░рдо рдореЗрдВ рдЕрдиреБрд╡рд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ:
	var query = listA.Join(listB, itemA => itemA.Key, itemB => itemB.Key, (itemA, itemB) => new {itemA, itemB});

рдФрд░ рдЗрд╕рд╕реЗ рдХреЛрдИ рдлрд░реНрдХ рдирд╣реАрдВ рдкрдбрд╝рддрд╛ рдХрд┐ рдХрд┐рд╕ рдкреНрд░рдХрд╛рд░ рдХреЗ рдЪрд░ рд╕реВрдЪреА рдФрд░ рд╕реВрдЪреА рдмреА рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ listA рдЯрд╛рдЗрдк рдХрд╛ рдПрдХ рд╡реИрд░рд┐рдПрдмрд▓ рд╣реИ, рдФрд░ рдкрд╛рд░рдЧрдореНрдп рдЖрдЗрдЯрдо рдмреА рдЯрд╛рдЗрдкрдмреА рдХрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдпрджрд┐ TypeA рдФрд░ TypeB рдореЗрдВ рдХреЛрдИ рдЧреБрдг рдпрд╛ рдлрд╝реАрд▓реНрдб рд╣реИ рдЬрд┐рд╕реЗ Key рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ TypeA рдореЗрдВ 4 рддрд░реНрдХреЛрдВ рдХреЗ рд╕рд╛рде Join () рд╡рд┐рдзрд┐ рд╢рд╛рдорд┐рд▓ рд╣реИред рдпрд╣ LINQ рдХреНрд╡реЗрд░реА рд╕реНрд╡рддрдВрддреНрд░ рд░реВрдк рд╕реЗ рд╕рдВрдХрд▓рд┐рдд рд╣реИред

LINQ рдореЗрдВ рд╡реИрд░рд┐рдПрдмрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп рдЬреЛ рдорд╛рдирдХ IEnumerable рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИ, рдПрдХреНрд╕рдЯреЗрдВрд╢рди рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ

public class System.Linq.Enumerable
{
		public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector) {...}
}

рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдпрд╣ рд╡рд┐рдзрд┐ рдкреНрд░рд╕рд┐рджреНрдз INNER JOIN рднреА рдмрдирд╛рддреА рд╣реИред рдФрд░ рдЕрдм рд╕реНрдЯреНрд░реАрдЯ рдореИрдЬрд┐рдХ рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИред LEFT / RIGHT / FULL OUTER JOIN (рдпрд╛ рдЬреЛрдЗрди рдЖрдкрдХреА рдЖрддреНрдорд╛ рдХреЛ рдкреНрд░рд╕рдиреНрди рдХрд░реЗрдЧрд╛) рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рд╣рдорд╛рд░реЗ рджреНрд╡рд╛рд░рд╛ рд▓рд╛рдЧреВ рдХрд┐рдП рдЧрдП рдорд╛рдирдХ рд╡рд┐рдзрд┐ рдХреА рдХреЙрд▓ рдХреЛ рдмрджрд▓рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдЪрд░ рд╕реВрдЪреА рдХреЛ рдХрд┐рд╕реА рдкреНрд░рдХрд╛рд░ рд╕реЗ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдо рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рджреЛ рд╡рд░реНрдЧреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдХреЗ:

public class JoinedEnumerable<T> : IEnumerable<T>
{
	public readonly IEnumerable<T> Source;
	public bool IsOuter;

	public JoinedEnumerable(IEnumerable<T> source) { Source = source; }

	IEnumerator<T> IEnumerable<T>.GetEnumerator() { return Source.GetEnumerator(); }
	IEnumerator IEnumerable.GetEnumerator() { return Source.GetEnumerator(); }
}

public static class JoinedEnumerable
{
	public static JoinedEnumerable<TElement> Inner<TElement>(this IEnumerable<TElement> source)
	{
		return Wrap(source, false);
	}

	public static JoinedEnumerable<TElement> Outer<TElement>(this IEnumerable<TElement> source)
	{
		return Wrap(source, true);
	}

	public static JoinedEnumerable<TElement> Wrap(IEnumerable<TElement> source, bool isOuter)
	{
		JoinedEnumerable<TElement> joinedSource 
			= source as JoinedEnumerable<TElement> ?? 
				new JoinedEnumerable<TElement>(source);
		joinedSource.IsOuter = isOuter;
		return joinedSource;
	}
}

рд╣рдо рдЖрд╕рд╛рдиреА рд╕реЗ рдЕрдЧрд▓реА LINQ рдХреНрд╡реЗрд░реА рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ

	var query = 
		from itemA in listA.Outer()
		join itemB in listB
			on itemA.Key equals itemB.Key
		select new {itemA, itemB};

рдФрд░ рдЕрдм JoinEnumerable рдХреНрд▓рд╛рд╕ рдХреЗ рд▓рд┐рдП рдЬреЙрдЗрди рдПрдХреНрд╕рдЯреЗрдВрд╢рди рд╡рд┐рдзрд┐ рдХреЛ рдЬрд┐рд╕ рддрд░рд╣ рд╕реЗ рд╣рдо рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЙрд╕ рдкрд░ рдЕрдорд▓ рдХрд░рддреЗ рд╣реБрдП, рд╣рдореЗрдВ рд╡рд╣ рд╕рдм рдХреБрдЫ рдЪрд╛рд╣рд┐рдП рдЬреЛ рд╣рдореЗрдВ рдЪрд╛рд╣рд┐рдПред

рдФрд░ рдпрд╣рд╛рдБ рд╡рд┐рд╕реНрддрд╛рд░ рд╡рд┐рдзрд┐рдпрд╛рдБ рд╣реИрдВ:

public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(this JoinedEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector, IEqualityComparer<TKey> comparer = null)
{
	if (outer == null) throw new ArgumentNullException("outer");
	if (inner == null) throw new ArgumentNullException("inner");
	if (outerKeySelector == null) throw new ArgumentNullException("outerKeySelector");
	if (innerKeySelector == null) throw new ArgumentNullException("innerKeySelector");
	if (resultSelector == null) throw new ArgumentNullException("resultSelector");

	bool leftOuter = outer.IsOuter;
	bool rightOuter = (inner is JoinedEnumerable<TInner>) && ((JoinedEnumerable<TInner>)inner).IsOuter;

	if (leftOuter && rightOuter)
		return FullOuterJoin(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);

	if (leftOuter)
		return LeftOuterJoin(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);

	if (rightOuter)
		return RightOuterJoin(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);

	return Enumerable.Join(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);
}

public static IEnumerable<TResult> LeftOuterJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector, IEqualityComparer<TKey> comparer = null)
{
	var innerLookup = inner.ToLookup(innerKeySelector, comparer);

	foreach (var outerItem in outer)
		foreach (var innerItem in innerLookup[outerKeySelector(outerItem)].DefaultIfEmpty())
			yield return resultSelector(outerItem, innerItem);
}

public static IEnumerable<TResult> RightOuterJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector, IEqualityComparer<TKey> comparer = null)
{
	var outerLookup = outer.ToLookup(outerKeySelector, comparer);

	foreach (var innerItem in inner)
		foreach (var outerItem in outerLookup[innerKeySelector(innerItem)].DefaultIfEmpty())
			yield return resultSelector(outerItem, innerItem);
}

public static IEnumerable<TResult> FullOuterJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector, IEqualityComparer<TKey> comparer = null)
{
	var outerLookup = outer.ToLookup(outerKeySelector, comparer);
	var innerLookup = inner.ToLookup(innerKeySelector, comparer);

	foreach (var innerGrouping in innerLookup)
		if (!outerLookup.Contains(innerGrouping.Key))
			foreach (TInner innerItem in innerGrouping)
				yield return resultSelector(default(TOuter), innerItem);

	foreach (var outerGrouping in outerLookup)
		foreach (var innerItem in innerLookup[outerGrouping.Key].DefaultIfEmpty())
			foreach (var outerItem in outerGrouping)
				yield return resultSelector(outerItem, innerItem);
}

рд╡реЛрдЗрд▓рд╛ ...

рд╕реБрдВрджрд░ рдмрд╛рдИрдВ рдУрд░

	var query = 
		from itemA in listA.Outer()
		join itemB in listB
			on itemA.Key equals itemB.Key
		select new {itemA, itemB};

рд╕реБрдВрджрд░ рд╕рд╣реА рдЬреВрдо:

	var query = 
		from itemA in listA.Inner()
		join itemB in listB.Outer()
			on itemA.Key equals itemB.Key
		select new {itemA, itemB};

рд╕реБрдВрджрд░ рдкреВрд░реНрдг рдЬреЙрдп рд╢рд╛рдорд┐рд▓:

	var query = 
		from itemA in listA.Outer()
		join itemB in listB.Outer()
			on itemA.Key equals itemB.Key
		select new {itemA, itemB};

рдЕрдм, рдпрджрд┐ рдЖрдк рдЪрд╛рд╣реЗрдВ, рддреЛ рдЖрдк рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ - рдХреНрдпреЛрдВрдХрд┐ рдХрд▓реНрдкрдирд╛ рдХреЗ рд▓рд┐рдП рдХреНрд╖реЗрддреНрд░ рдпрд╣рд╛рдВ рдмрд╣реБрдд рдмрдбрд╝рд╛ рд╣реИред рдореЗрд░реЗ рдкрд╛рд╕ рдЬрд╝рд╛рд╢реНрд╢реНрдирд┐рдХ рдореЗрдВ рдЕрдЪреНрдЫрд╛рдЗрдпреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрдИ рдФрд░ рджрд┐рд▓рдЪрд╕реНрдк рд╕рдорд╛рдзрд╛рди рд╣реИрдВред рдЙрдиреНрд╣реЗрдВ рд╕рд╛рдЭрд╛ рдХрд░рдиреЗ рдХрд╛ рд╕рдордп рд╣реЛрдЧрд╛ред

рдзреНрдпрд╛рди рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдзрдиреНрдпрд╡рд╛рджред

рдЖрдкрдХреЗ рд╕рд╛рде рд╣реЛ рд╕рдХрддрд╛ рд╣реИ!

All Articles