diff UnitTests/Linq/GroupByTest.cs @ 0:f990fcb411a9

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UnitTests/Linq/GroupByTest.cs	Thu Mar 27 21:46:09 2014 +0400
@@ -0,0 +1,1535 @@
+using System;
+using System.Linq;
+
+using NUnit.Framework;
+
+using BLToolkit.Data.DataProvider;
+
+namespace Data.Linq
+{
+	using Model;
+
+	[TestFixture]
+	public class GroupByTest : TestBase
+	{
+		[Test]
+		public void Simple1()
+		{
+			BLToolkit.Common.Configuration.Linq.PreloadGroups = true;
+
+			ForEachProvider(db =>
+			{
+				var q =
+					from ch in db.Child
+					group ch by ch.ParentID;
+
+				var list = q.ToList().Where(n => n.Key < 6).OrderBy(n => n.Key).ToList();
+
+				Assert.AreEqual(4, list.Count);
+
+				for (var i = 0; i < list.Count; i++)
+				{
+					var values = list[i].OrderBy(c => c.ChildID).ToList();
+
+					Assert.AreEqual(i + 1, list[i].Key);
+					Assert.AreEqual(i + 1, values.Count);
+
+					for (var j = 0; j < values.Count; j++)
+						Assert.AreEqual((i + 1) * 10 + j + 1, values[j].ChildID);
+				}
+			});
+		}
+
+		[Test]
+		public void Simple2()
+		{
+			BLToolkit.Common.Configuration.Linq.PreloadGroups = false;
+
+			ForEachProvider(db =>
+			{
+				var q =
+					from ch in db.GrandChild
+					group ch by new { ch.ParentID, ch.ChildID };
+
+				var list = q.ToList();
+
+				Assert.AreEqual   (8, list.Count);
+				Assert.AreNotEqual(0, list.OrderBy(c => c.Key.ParentID).First().ToList().Count);
+			});
+		}
+
+		[Test]
+		public void Simple3()
+		{
+			ForEachProvider(db =>
+			{
+				var q =
+					from ch in db.Child
+					group ch by ch.ParentID into g
+					select g.Key;
+
+				var list = q.ToList().Where(n => n < 6).OrderBy(n => n).ToList();
+
+				Assert.AreEqual(4, list.Count);
+				for (var i = 0; i < list.Count; i++) Assert.AreEqual(i + 1, list[i]);
+			});
+		}
+
+		[Test]
+		public void Simple4()
+		{
+			ForEachProvider(db =>
+			{
+				var q =
+					from ch in db.Child
+					group ch by ch.ParentID into g
+					orderby g.Key
+					select g.Key;
+
+				var list = q.ToList().Where(n => n < 6).ToList();
+
+				Assert.AreEqual(4, list.Count);
+				for (var i = 0; i < list.Count; i++) Assert.AreEqual(i + 1, list[i]);
+			});
+		}
+
+		[Test]
+		public void Simple5()
+		{
+			var expected =
+				from ch in GrandChild
+				group ch by new { ch.ParentID, ch.ChildID } into g
+				group g  by new { g.Key.ParentID }          into g
+				select g.Key;
+
+			ForEachProvider(db => AreEqual(expected,
+				from ch in db.GrandChild
+				group ch by new { ch.ParentID, ch.ChildID } into g
+				group g  by new { g.Key.ParentID }          into g
+				select g.Key));
+		}
+
+		[Test]
+		public void Simple6()
+		{
+			ForEachProvider(db =>
+			{
+				var q    = db.GrandChild.GroupBy(ch => new { ch.ParentID, ch.ChildID }, ch => ch.GrandChildID);
+				var list = q.ToList();
+
+				Assert.AreNotEqual(0, list[0].Count());
+				Assert.AreEqual   (8, list.Count);
+			});
+		}
+
+		[Test]
+		public void Simple7()
+		{
+			ForEachProvider(db =>
+			{
+				var q = db.GrandChild
+					.GroupBy(ch => new { ch.ParentID, ch.ChildID }, ch => ch.GrandChildID)
+					.Select (gr => new { gr.Key.ParentID, gr.Key.ChildID });
+
+				var list = q.ToList();
+				Assert.AreEqual(8, list.Count);
+			});
+		}
+
+		[Test]
+		public void Simple8()
+		{
+			ForEachProvider(db =>
+			{
+				var q = db.GrandChild.GroupBy(ch => new { ch.ParentID, ch.ChildID }, (g,ch) => g.ChildID);
+
+				var list = q.ToList();
+				Assert.AreEqual(8, list.Count);
+			});
+		}
+
+		[Test]
+		public void Simple9()
+		{
+			ForEachProvider(db =>
+			{
+				var q    = db.GrandChild.GroupBy(ch => new { ch.ParentID, ch.ChildID }, ch => ch.GrandChildID,  (g,ch) => g.ChildID);
+				var list = q.ToList();
+
+				Assert.AreEqual(8, list.Count);
+			});
+		}
+
+		[Test]
+		public void Simple10()
+		{
+			var expected = (from ch in Child group ch by ch.ParentID into g select g).ToList().OrderBy(p => p.Key).ToList();
+
+			ForEachProvider(db =>
+			{
+				var result = (from ch in db.Child group ch by ch.ParentID into g select g).ToList().OrderBy(p => p.Key).ToList();
+
+				AreEqual(expected[0], result[0]);
+				AreEqual(expected.Select(p => p.Key), result.Select(p => p.Key));
+				AreEqual(expected[0].ToList(), result[0].ToList());
+			});
+		}
+
+		[Test]
+		public void Simple11()
+		{
+			ForEachProvider(db =>
+			{
+				var q1 = GrandChild
+					.GroupBy(ch => new { ParentID = ch.ParentID + 1, ch.ChildID }, ch => ch.ChildID);
+
+				var q2 = db.GrandChild
+					.GroupBy(ch => new { ParentID = ch.ParentID + 1, ch.ChildID }, ch => ch.ChildID);
+
+				var list1 = q1.AsEnumerable().OrderBy(_ => _.Key.ChildID).ToList();
+				var list2 = q2.AsEnumerable().OrderBy(_ => _.Key.ChildID).ToList();
+
+				Assert.AreEqual(list1.Count,       list2.Count);
+				Assert.AreEqual(list1[0].ToList(), list2[0].ToList());
+			});
+		}
+
+		[Test]
+		public void Simple12()
+		{
+			ForEachProvider(db =>
+			{
+				var q = db.GrandChild
+					.GroupBy(ch => new { ParentID = ch.ParentID + 1, ch.ChildID }, (g,ch) => g.ChildID);
+
+				var list = q.ToList();
+				Assert.AreEqual(8, list.Count);
+			});
+		}
+
+		[Test]
+		public void Simple13()
+		{
+			ForEachProvider(db =>
+			{
+				var q = db.GrandChild
+					.GroupBy(ch => new { ParentID = ch.ParentID + 1, ch.ChildID }, ch => ch.ChildID, (g,ch) => g.ChildID);
+
+				var list = q.ToList();
+				Assert.AreEqual(8, list.Count);
+			});
+		}
+
+		//[Test]
+		public void Simple14()
+		{
+			ForEachProvider(db => AreEqual(
+				from p in    Parent
+				select
+					from c in p.Children
+					group c by c.ParentID into g
+					select g.Key,
+				from p in db.Parent
+				select
+					from c in p.Children
+					group c by c.ParentID into g
+					select g.Key));
+		}
+
+		[Test]
+		public void MemberInit1()
+		{
+			ForEachProvider(db => AreEqual(
+				from ch in Child
+				group ch by new Child { ParentID = ch.ParentID } into g
+				select g.Key,
+				from ch in db.Child
+				group ch by new Child { ParentID = ch.ParentID } into g
+				select g.Key));
+		}
+
+		class GroupByInfo
+		{
+			public GroupByInfo Prev;
+			public object      Field;
+
+			public override bool Equals(object obj)
+			{
+				return Equals(obj as GroupByInfo);
+			}
+
+			public bool Equals(GroupByInfo other)
+			{
+				if (ReferenceEquals(null, other)) return false;
+				if (ReferenceEquals(this, other)) return true;
+				return Equals(other.Prev, Prev) && Equals(other.Field, Field);
+			}
+
+			public override int GetHashCode()
+			{
+				unchecked
+				{
+					return ((Prev != null ? Prev.GetHashCode() : 0) * 397) ^ (Field != null ? Field.GetHashCode() : 0);
+				}
+			}
+		}
+
+		[Test]
+		public void MemberInit2()
+		{
+			ForEachProvider(db => AreEqual(
+				from ch in Child
+				group ch by new GroupByInfo { Prev = new GroupByInfo { Field = ch.ParentID }, Field = ch.ChildID } into g
+				select g.Key,
+				from ch in db.Child
+				group ch by new GroupByInfo { Prev = new GroupByInfo { Field = ch.ParentID }, Field = ch.ChildID } into g
+				select g.Key));
+		}
+
+		[Test]
+		public void MemberInit3()
+		{
+			ForEachProvider(db => AreEqual(
+				from ch in Child
+				group ch by new { Prev = new { Field = ch.ParentID }, Field = ch.ChildID } into g
+				select g.Key,
+				from ch in db.Child
+				group ch by new { Prev = new { Field = ch.ParentID }, Field = ch.ChildID } into g
+				select g.Key));
+		}
+
+		[Test]
+		public void SubQuery1()
+		{
+			var n = 1;
+
+			var expected =
+				from ch in
+					from ch in Child select ch.ParentID + 1
+				where ch + 1 > n
+				group ch by ch into g
+				select g.Key;
+
+			ForEachProvider(db => AreEqual(expected,
+				from ch in
+					from ch in db.Child select ch.ParentID + 1
+				where ch > n
+				group ch by ch into g
+				select g.Key));
+		}
+
+		[Test]
+		public void SubQuery2()
+		{
+			var n = 1;
+
+			var expected =
+				from ch in Child select new { ParentID = ch.ParentID + 1 } into ch
+				where ch.ParentID > n
+				group ch by ch into g
+				select g.Key;
+
+			ForEachProvider(db => AreEqual(expected,
+				from ch in db.Child select new { ParentID = ch.ParentID + 1 } into ch
+				where ch.ParentID > n
+				group ch by ch into g
+				select g.Key));
+		}
+
+		[Test]
+		public void SubQuery3()
+		{
+			ForEachProvider(db => AreEqual(
+				from ch in
+					from ch in Child
+					select new { ch, n = ch.ChildID + 1 }
+				group ch by ch.n into g
+				select new
+				{
+					g.Key,
+					Sum = g.Sum(_ => _.ch.ParentID)
+				},
+				from ch in
+					from ch in db.Child
+					select new { ch, n = ch.ChildID + 1 }
+				group ch by ch.n into g
+				select new
+				{
+					g.Key,
+					Sum = g.Sum(_ => _.ch.ParentID)
+				}));
+		}
+
+		[Test]
+		public void SubQuery31()
+		{
+			ForEachProvider(db => AreEqual(
+				from ch in
+					from ch in Child
+					select new { ch, n = ch.ChildID + 1 }
+				group ch.ch by ch.n into g
+				select new
+				{
+					g.Key,
+					Sum = g.Sum(_ => _.ParentID)
+				},
+				from ch in
+					from ch in db.Child
+					select new { ch, n = ch.ChildID + 1 }
+				group ch.ch by ch.n into g
+				select new
+				{
+					g.Key,
+					Sum = g.Sum(_ => _.ParentID)
+				}));
+		}
+
+		[Test]
+		public void SubQuery32()
+		{
+			ForEachProvider(db => AreEqual(
+				from ch in
+					from ch in Child
+					select new { ch, n = ch.ChildID + 1 }
+				group ch.ch.ParentID by ch.n into g
+				select new
+				{
+					g.Key,
+					Sum = g.Sum(_ => _)
+				},
+				from ch in
+					from ch in db.Child
+					select new { ch, n = ch.ChildID + 1 }
+				group ch.ch.ParentID by ch.n into g
+				select new
+				{
+					g.Key,
+					Sum = g.Sum(_ => _)
+				}));
+		}
+
+		[Test]
+		public void SubQuery4()
+		{
+			ForEachProvider(db => AreEqual(
+				from ch in Child
+				group ch by new { n = ch.ChildID + 1 } into g
+				select new
+				{
+					g.Key,
+					Sum = g.Sum(_ => _.ParentID)
+				},
+				from ch in db.Child
+				group ch by new { n = ch.ChildID + 1 } into g
+				select new
+				{
+					g.Key,
+					Sum = g.Sum(_ => _.ParentID)
+				}));
+		}
+
+		[Test]
+		public void SubQuery5()
+		{
+			ForEachProvider(db => AreEqual(
+				from ch in Child
+				join p in Parent on ch.ParentID equals p.ParentID into pg
+				from p in pg.DefaultIfEmpty()
+				group ch by ch.ChildID into g
+				select g.Sum(_ => _.ParentID),
+				from ch in db.Child
+				join p in db.Parent on ch.ParentID equals p.ParentID into pg
+				from p in pg.DefaultIfEmpty()
+				group ch by ch.ChildID into g
+				select g.Sum(_ => _.ParentID)));
+		}
+
+		[Test]
+		public void SubQuery6()
+		{
+			var expected =
+				from ch in Child select new { ParentID = ch.ParentID + 1 } into ch
+				group ch.ParentID by ch into g
+				select g.Key;
+
+			ForEachProvider(db => AreEqual(expected,
+				from ch in db.Child select new { ParentID = ch.ParentID + 1 } into ch
+				group ch.ParentID by ch into g
+				select g.Key));
+		}
+
+		[Test]
+		public void SubQuery7()
+		{
+			ForEachProvider(db => AreEqual(
+				from p in Parent
+				join c in 
+					from c in Child
+					where c.ParentID == 1
+					select c
+				on p.ParentID equals c.ParentID into g
+				from c in g.DefaultIfEmpty()
+				group p by c == null ? 0 : c.ChildID into gg
+				select new { gg.Key },
+				from p in db.Parent
+				join c in 
+					from c in db.Child
+					where c.ParentID == 1
+					select c
+				on p.ParentID equals c.ParentID into g
+				from c in g.DefaultIfEmpty()
+				group p by c.ChildID into gg
+				select new { gg.Key }));
+		}
+
+		[Test]
+		public void Calculated1()
+		{
+			var expected = 
+				(
+					from ch in Child
+					group ch by ch.ParentID > 2 ? ch.ParentID > 3 ? "1" : "2" : "3"
+					into g select g
+				).ToList().OrderBy(p => p.Key).ToList();
+
+			ForEachProvider(db =>
+			{
+				var result =
+					(
+						from ch in db.Child
+						group ch by ch.ParentID > 2 ? ch.ParentID > 3 ? "1" : "2" : "3"
+						into g select g
+					).ToList().OrderBy(p => p.Key).ToList();
+
+				AreEqual(expected[0], result[0]);
+				AreEqual(expected.Select(p => p.Key), result.Select(p => p.Key));
+			});
+		}
+
+		[Test]
+		public void Calculated2()
+		{
+			var expected =
+				from p in
+					from ch in
+						from ch in Child
+						group ch by ch.ParentID > 2 ? ch.ParentID > 3 ? "1" : "2" : "3"
+						into g select g
+					select ch.Key + "2"
+				where p == "22"
+				select p;
+
+			ForEachProvider(db => AreEqual(expected,
+				from p in
+					from ch in
+						from ch in db.Child
+						group ch by ch.ParentID > 2 ? ch.ParentID > 3 ? "1" : "2" : "3"
+						into g select g
+					select ch.Key + "2"
+				where p == "22"
+				select p));
+		}
+
+		[Test]
+		public void GroupBy1()
+		{
+			ForEachProvider(db => AreEqual(
+				   Child.GroupBy(ch => ch.ParentID).GroupBy(ch => ch).GroupBy(ch => ch).Select(p => p.Key.Key.Key),
+				db.Child.GroupBy(ch => ch.ParentID).GroupBy(ch => ch).GroupBy(ch => ch).Select(p => p.Key.Key.Key)));
+		}
+
+		[Test]
+		public void GroupBy2()
+		{
+			ForEachProvider(db => AreEqual(
+				from p in Parent
+				join c in Child on p.ParentID equals c.ParentID
+				group p by new
+				{
+					ID = p.Value1 ?? c.ChildID
+				} into gr
+				select new
+				{
+					gr.Key.ID,
+					ID1 = gr.Key.ID + 1,
+				},
+				from p in db.Parent
+				join c in db.Child on p.ParentID equals c.ParentID
+				group p by new
+				{
+					ID = p.Value1 ?? c.ChildID
+				} into gr
+				select new
+				{
+					gr.Key.ID,
+					ID1 = gr.Key.ID + 1,
+				}));
+		}
+
+		[Test]
+		public void GroupBy3()
+		{
+			ForEachProvider(db => AreEqual(
+				from p in Parent
+				join c in Child on p.ParentID equals c.ParentID
+				group p by p.Value1 ?? c.ChildID into gr
+				select new
+				{
+					gr.Key
+				},
+				from p in db.Parent
+				join c in db.Child on p.ParentID equals c.ParentID
+				group p by p.Value1 ?? c.ChildID into gr
+				select new
+				{
+					gr.Key
+				}));
+		}
+
+		[Test]
+		public void Sum1()
+		{
+			var expected =
+				from ch in Child
+				group ch by ch.ParentID into g
+				select g.Sum(p => p.ChildID);
+
+			ForEachProvider(db => AreEqual(expected,
+				from ch in db.Child
+				group ch by ch.ParentID into g
+				select g.Sum(p => p.ChildID)));
+		}
+
+		[Test]
+		public void Sum2()
+		{
+			var expected =
+				from ch in Child
+				group ch by ch.ParentID into g
+				select new { Sum = g.Sum(p => p.ChildID) };
+
+			ForEachProvider(db => AreEqual(expected,
+				from ch in db.Child
+				group ch by ch.ParentID into g
+				select new { Sum = g.Sum(p => p.ChildID) }));
+		}
+
+		[Test]
+		public void Sum3()
+		{
+			ForEachProvider(
+				new[] { ProviderName.SqlCe },
+				db => AreEqual(
+					from ch in Child
+					group ch by ch.Parent into g
+					select g.Key.Children.Sum(p => p.ChildID),
+					from ch in db.Child
+					group ch by ch.Parent into g
+					select g.Key.Children.Sum(p => p.ChildID)));
+		}
+
+		[Test]
+		public void SumSubQuery1()
+		{
+			var n = 1;
+
+			var expected =
+				from ch in
+					from ch in Child select new { ParentID = ch.ParentID + 1, ch.ChildID }
+				where ch.ParentID + 1 > n group ch by ch into g
+				select g.Sum(p => p.ParentID - 3);
+
+			ForEachProvider(db => AreEqual(expected,
+				from ch in
+					from ch in db.Child select new { ParentID = ch.ParentID + 1, ch.ChildID }
+				where ch.ParentID + 1 > n group ch by ch into g
+				select g.Sum(p => p.ParentID - 3)));
+		}
+
+		[Test]
+		public void GroupByMax()
+		{
+			ForEachProvider(db => AreEqual(
+				from ch in    Child group ch.ParentID by ch.ChildID into g select new { Max = g.Max() },
+				from ch in db.Child group ch.ParentID by ch.ChildID into g select new { Max = g.Max() }));
+		}
+
+		[Test]
+		public void Aggregates1()
+		{
+			ForEachProvider(db => AreEqual(
+				from  ch in Child
+				group ch by ch.ParentID into g
+				select new
+				{
+					Cnt = g.Count(),
+					Sum = g.Sum(c => c.ChildID),
+					Min = g.Min(c => c.ChildID),
+					Max = g.Max(c => c.ChildID),
+					Avg = (int)g.Average(c => c.ChildID),
+				},
+				from  ch in db.Child
+				group ch by ch.ParentID into g
+				select new
+				{
+					Cnt = g.Count(),
+					Sum = g.Sum(c => c.ChildID),
+					Min = g.Min(c => c.ChildID),
+					Max = g.Max(c => c.ChildID),
+					Avg = (int)g.Average(c => c.ChildID),
+				}));
+		}
+
+		[Test]
+		public void Aggregates2()
+		{
+			ForEachProvider(db => AreEqual(
+				from  ch in Child
+				group ch by ch.ParentID into g
+				select new
+				{
+					Sum = g.Select(c => c.ChildID).Sum(),
+					Min = g.Select(c => c.ChildID).Min(),
+					Max = g.Select(c => c.ChildID).Max(),
+					Avg = (int)g.Select(c => c.ChildID).Average(),
+					Cnt = g.Count()
+				},
+				from  ch in db.Child
+				group ch by ch.ParentID into g
+				select new
+				{
+					Sum = g.Select(c => c.ChildID).Sum(),
+					Min = g.Select(c => c.ChildID).Min(),
+					Max = g.Select(c => c.ChildID).Max(),
+					Avg = (int)g.Select(c => c.ChildID).Average(),
+					Cnt = g.Count()
+				}));
+		}
+
+		[Test]
+		public void Aggregates3()
+		{
+			ForEachProvider(
+				new[] { ProviderName.SqlCe },
+				db => AreEqual(
+					from  ch in Child
+					where ch.ChildID > 30
+					group ch by ch.ParentID into g
+					select new
+					{
+						Sum =      g.Select(c => c.ChildID).Where(_ => _ > 30).Sum(),
+						Min =      g.Select(c => c.ChildID).Where(_ => _ > 30).Min(),
+						Max =      g.Select(c => c.ChildID).Where(_ => _ > 30).Max(),
+						Avg = (int)g.Select(c => c.ChildID).Where(_ => _ > 30).Average(),
+					},
+					from  ch in db.Child
+					where ch.ChildID > 30
+					group ch by ch.ParentID into g
+					select new
+					{
+						Sum =      g.Select(c => c.ChildID).Where(_ => _ > 30).Sum(),
+						Min =      g.Select(c => c.ChildID).Where(_ => _ > 30).Min(),
+						Max =      g.Select(c => c.ChildID).Where(_ => _ > 30).Max(),
+						Avg = (int)g.Select(c => c.ChildID).Where(_ => _ > 30).Average(),
+					}));
+		}
+
+		[Test]
+		public void Aggregates4()
+		{
+			ForEachProvider(
+				new[] { ProviderName.SqlCe },
+				db => AreEqual(
+					from  ch in Child
+					group ch by ch.ParentID into g
+					select new
+					{
+						Count = g.Count(_ => _.ChildID > 30),
+						Sum   = g.Where(_ => _.ChildID > 30).Sum(c => c.ChildID),
+					},
+					from  ch in db.Child
+					group ch by ch.ParentID into g
+					select new
+					{
+						Count = g.Count(_ => _.ChildID > 30),
+						Sum   = g.Where(_ => _.ChildID > 30).Sum(c => c.ChildID),
+					}));
+		}
+
+		[Test]
+		public void SelectMax()
+		{
+			var expected =
+				from ch in Child
+				group ch by ch.ParentID into g
+				select g.Max(c => c.ChildID);
+
+			ForEachProvider(db => AreEqual(expected,
+				from ch in db.Child
+				group ch by ch.ParentID into g
+				select g.Max(c => c.ChildID)));
+		}
+
+		[Test]
+		public void JoinMax()
+		{
+			var expected =
+				from ch in Child
+					join max in
+						from ch in Child
+						group ch by ch.ParentID into g
+						select g.Max(c => c.ChildID)
+					on ch.ChildID equals max
+				select ch;
+
+			ForEachProvider(db => AreEqual(expected,
+				from ch in db.Child
+					join max in
+						from ch in db.Child
+						group ch by ch.ParentID into g
+						select g.Max(c => c.ChildID)
+					on ch.ChildID equals max
+				select ch));
+		}
+
+		[Test]
+		public void Min1()
+		{
+			var expected = Child.Min(c => c.ChildID);
+			ForEachProvider(db => Assert.AreEqual(expected, db.Child.Min(c => c.ChildID)));
+		}
+
+		[Test]
+		public void Min2()
+		{
+			var expected = Child.Select(c => c.ChildID).Min();
+			ForEachProvider(db => Assert.AreEqual(expected, db.Child.Select(c => c.ChildID).Min()));
+		}
+
+		[Test]
+		public void Max1()
+		{
+			var expected = Child.Max(c => c.ChildID);
+			Assert.AreNotEqual(0, expected);
+			ForEachProvider(db => Assert.AreEqual(expected, db.Child.Max(c => c.ChildID)));
+		}
+
+		[Test]
+		public void Max11()
+		{
+			ForEachProvider(db => Assert.AreEqual(
+				   Child.Max(c => c.ChildID > 20),
+				db.Child.Max(c => c.ChildID > 20)));
+		}
+
+		[Test]
+		public void Max12()
+		{
+			ForEachProvider(db => Assert.AreEqual(
+				   Child.Max(c => (bool?)(c.ChildID > 20)),
+				db.Child.Max(c => (bool?)(c.ChildID > 20))));
+		}
+
+		[Test]
+		public void Max2()
+		{
+			var expected =
+				from p in Parent
+					join c in Child on p.ParentID equals c.ParentID
+				where c.ChildID > 20
+				select p;
+
+			ForEachProvider(db =>
+			{
+				var result =
+					from p in db.Parent
+						join c in db.Child on p.ParentID equals c.ParentID
+					where c.ChildID > 20
+					select p;
+
+				Assert.AreEqual(expected.Max(p => p.ParentID), result.Max(p => p.ParentID));
+			});
+		}
+
+		[Test]
+		public void Max3()
+		{
+			ForEachProvider(db => Assert.AreEqual(
+				Child.Select(c => c.ChildID).Max(),
+				db.Child.Select(c => c.ChildID).Max()));
+		}
+
+		[Test]
+		public void Max4()
+		{
+			ForEachProvider(db => Assert.AreEqual(
+				from t1 in Types
+				join t2 in
+					from sub in Types
+					where
+						sub.ID == 1 &&
+						sub.DateTimeValue <= DateTime.Today
+					group sub by new
+					{
+						sub.ID
+					} into g
+					select new
+					{
+						g.Key.ID,
+						DateTimeValue = g.Max( p => p.DateTimeValue )
+					}
+				on new { t1.ID, t1.DateTimeValue } equals new { t2.ID, t2.DateTimeValue }
+				select t1.MoneyValue,
+				from t1 in db.Types
+				join t2 in
+					from sub in db.Types
+					where
+						sub.ID == 1 &&
+						sub.DateTimeValue <= DateTime.Today
+					group sub by new
+					{
+						sub.ID
+					} into g
+					select new
+					{
+						g.Key.ID,
+						DateTimeValue = g.Max( p => p.DateTimeValue )
+					}
+				on new { t1.ID, t1.DateTimeValue } equals new { t2.ID, t2.DateTimeValue }
+				select t1.MoneyValue
+				));
+		}
+
+		[Test]
+		public void Average1()
+		{
+			ForEachProvider(db => Assert.AreEqual(
+				(int)db.Child.Average(c => c.ChildID),
+				(int)   Child.Average(c => c.ChildID)));
+		}
+
+		[Test]
+		public void Average2()
+		{
+			var expected = Child.Select(c => c.ChildID).Average();
+			ForEachProvider(db => Assert.AreEqual((int)expected, (int)db.Child.Select(c => c.ChildID).Average()));
+		}
+
+		[Test]
+		public void GrooupByAssociation1()
+		{
+			ForEachProvider(db => AreEqual(
+				from ch in GrandChild1
+				group ch by ch.Parent into g
+				where g.Count() > 2
+				select g.Key.Value1
+				,
+				from ch in db.GrandChild1
+				group ch by ch.Parent into g
+				where g.Count() > 2
+				select g.Key.Value1));
+		}
+
+		[Test]
+		public void GrooupByAssociation101()
+		{
+			ForEachProvider(db => AreEqual(
+				from ch in GrandChild1
+				group ch by ch.Parent into g
+				where g.Max(_ => _.ParentID) > 2
+				select g.Key.Value1
+				,
+				from ch in db.GrandChild1
+				group ch by ch.Parent into g
+				where g.Max(_ => _.ParentID) > 2
+				select g.Key.Value1));
+		}
+
+		[Test]
+		public void GrooupByAssociation102()
+		{
+			ForEachProvider(
+				new[] { ProviderName.Informix },
+				db => AreEqual(
+					from ch in GrandChild1
+					group ch by ch.Parent into g
+					where g.Count(_ => _.ChildID >= 20) > 2
+					select g.Key.Value1
+					,
+					from ch in db.GrandChild1
+					group ch by ch.Parent into g
+					where g.Count(_ => _.ChildID >= 20) > 2
+					select g.Key.Value1));
+		}
+
+		[Test]
+		public void GrooupByAssociation1022()
+		{
+			ForEachProvider(
+				new[] { ProviderName.SqlCe, ProviderName.Access, ProviderName.Informix }, // Can be fixed.
+					db => AreEqual(
+					from ch in GrandChild1
+					group ch by ch.Parent into g
+					where g.Count(_ => _.ChildID >= 20) > 2 && g.Where(_ => _.ChildID >= 19).Sum(p => p.ParentID) > 0
+					select g.Key.Value1
+					,
+					from ch in db.GrandChild1
+					group ch by ch.Parent into g
+					where g.Count(_ => _.ChildID >= 20) > 2 && g.Where(_ => _.ChildID >= 19).Sum(p => p.ParentID) > 0
+					select g.Key.Value1));
+		}
+
+		[Test]
+		public void GrooupByAssociation1023()
+		{
+			ForEachProvider(
+				new[] { ProviderName.SqlCe, ProviderName.Access, ProviderName.Informix }, // Can be fixed.
+				db => AreEqual(
+					from ch in GrandChild1
+					group ch by ch.Parent into g
+					where
+						g.Count(_ => _.ChildID >= 20) > 2 &&
+						g.Where(_ => _.ChildID >= 19).Sum(p => p.ParentID) > 0 &&
+						g.Where(_ => _.ChildID >= 19).Max(p => p.ParentID) > 0
+					select g.Key.Value1
+					,
+					from ch in db.GrandChild1
+					group ch by ch.Parent into g
+					where
+						g.Count(_ => _.ChildID >= 20) > 2 &&
+						g.Where(_ => _.ChildID >= 19).Sum(p => p.ParentID) > 0 &&
+						g.Where(_ => _.ChildID >= 19).Max(p => p.ParentID) > 0
+					select g.Key.Value1));
+		}
+
+		[Test]
+		public void GrooupByAssociation1024()
+		{
+			ForEachProvider(
+				new[] { ProviderName.SqlCe, ProviderName.Access, ProviderName.Informix }, // Can be fixed.
+				db => AreEqual(
+					from ch in GrandChild1
+					group ch by ch.Parent into g
+					where
+						g.Count(_ => _.ChildID >= 20) > 2 &&
+						g.Where(_ => _.ChildID >= 19).Sum(p => p.ParentID) > 0 &&
+						g.Where(_ => _.ChildID >= 19).Max(p => p.ParentID) > 0 &&
+						g.Where(_ => _.ChildID >= 18).Max(p => p.ParentID) > 0
+					select g.Key.Value1
+					,
+					from ch in db.GrandChild1
+					group ch by ch.Parent into g
+					where
+						g.Count(_ => _.ChildID >= 20) > 2 &&
+						g.Where(_ => _.ChildID >= 19).Sum(p => p.ParentID) > 0 &&
+						g.Where(_ => _.ChildID >= 19).Max(p => p.ParentID) > 0 &&
+						g.Where(_ => _.ChildID >= 18).Max(p => p.ParentID) > 0
+					select g.Key.Value1));
+		}
+
+		[Test]
+		public void GrooupByAssociation2()
+		{
+			ForEachProvider(db => AreEqual(
+				from ch in GrandChild1
+				group ch by ch.Parent into g
+				where g.Count() > 2 && g.Key.ParentID != 1
+				select g.Key.Value1
+				,
+				from ch in db.GrandChild1
+				group ch by ch.Parent into g
+				where g.Count() > 2 && g.Key.ParentID != 1
+				select g.Key.Value1));
+		}
+
+		[Test]
+		public void GrooupByAssociation3([IncludeDataContexts("Northwind")] string context)
+		{
+			using (var db = new NorthwindDB())
+			{
+				var result = 
+					from p in db.Product
+					group p by p.Category into g
+					where g.Count() == 12
+					select g.Key.CategoryName;
+
+				var list = result.ToList();
+				Assert.AreEqual(3, list.Count);
+			}
+		}
+
+		[Test]
+		public void GrooupByAssociation4([IncludeDataContexts("Northwind")] string context)
+		{
+			using (var db = new NorthwindDB())
+			{
+				var result = 
+					from p in db.Product
+					group p by p.Category into g
+					where g.Count() == 12
+					select g.Key.CategoryID;
+
+				var list = result.ToList();
+				Assert.AreEqual(3, list.Count);
+			}
+		}
+
+		[Test]
+		public void GroupByAggregate1()
+		{
+			var expected =
+				from p in Parent
+				group p by p.Children.Count > 0 && p.Children.Average(c => c.ParentID) > 3 into g
+				select g.Key;
+
+			ForEachProvider(new[] { ProviderName.SqlCe }, db => AreEqual(expected,
+				from p in db.Parent
+				group p by p.Children.Average(c => c.ParentID) > 3 into g
+				select g.Key));
+		}
+
+		[Test]
+		public void GroupByAggregate11()
+		{
+			var expected =
+				from p in Parent
+				where p.Children.Count > 0
+				group p by p.Children.Average(c => c.ParentID) > 3 into g
+				select g.Key;
+
+			ForEachProvider(new[] { ProviderName.SqlCe }, db => AreEqual(expected,
+				from p in db.Parent
+				where p.Children.Count > 0
+				group p by p.Children.Average(c => c.ParentID) > 3 into g
+				select g.Key));
+		}
+
+		[Test]
+		public void GroupByAggregate12()
+		{
+			var expected =
+				from p in Parent
+				group p by p.Children.Count > 0 && p.Children.Average(c => c.ParentID) > 3 into g
+				select g.Key;
+
+			ForEachProvider(new[] { ProviderName.SqlCe }, db => AreEqual(expected,
+				from p in db.Parent
+				group p by p.Children.Count > 0 && p.Children.Average(c => c.ParentID) > 3 into g
+				select g.Key));
+		}
+
+		[Test]
+		public void GroupByAggregate2([IncludeDataContexts("Northwind")] string context)
+		{
+			using (var db = new NorthwindDB())
+				AreEqual(
+					(
+						from c in Customer
+						group c by c.Orders.Count > 0 && c.Orders.Average(o => o.Freight) >= 80
+					).ToList().Select(k => k.Key),
+					(
+						from c in db.Customer
+						group c by c.Orders.Average(o => o.Freight) >= 80
+					).ToList().Select(k => k.Key));
+		}
+
+		[Test]
+		public void GroupByAggregate3()
+		{
+			var expected =
+				(
+					from p in Parent
+					group p by p.Children.Count > 0 && p.Children.Average(c => c.ParentID) > 3
+				).ToList().First(g => !g.Key);
+
+			ForEachProvider(new[] { ProviderName.SqlCe }, db => AreEqual(expected,
+				(
+					from p in db.Parent
+					group p by p.Children.Average(c => c.ParentID) > 3
+				).ToList().First(g => !g.Key)));
+		}
+
+		[Test]
+		public void ByJoin()
+		{
+			ForEachProvider(db => AreEqual(
+				from c1 in Child
+				join c2 in Child on c1.ChildID equals c2.ChildID + 1
+				group c2 by c1.ParentID into g
+				select g.Sum(_ => _.ChildID),
+				from c1 in db.Child
+				join c2 in db.Child on c1.ChildID equals c2.ChildID + 1
+				group c2 by c1.ParentID into g
+				select g.Sum(_ => _.ChildID)));
+		}
+
+		[Test]
+		public void SelectMany()
+		{
+			ForEachProvider(db => AreEqual(
+				   Child.GroupBy(ch => ch.ParentID).SelectMany(g => g),
+				db.Child.GroupBy(ch => ch.ParentID).SelectMany(g => g)));
+		}
+
+		[Test]
+		public void Scalar1()
+		{
+			ForEachProvider(new[] { ProviderName.SqlCe }, db => AreEqual(
+				(from ch in Child
+				 group ch by ch.ParentID into g
+				 select g.Select(ch => ch.ChildID).Max()),
+				(from ch in db.Child
+				 group ch by ch.ParentID into g
+				 select g.Select(ch => ch.ChildID).Max())));
+		}
+
+		[Test]
+		public void Scalar101()
+		{
+			ForEachProvider(db => AreEqual(
+				(from ch in Child
+				 select ch.ChildID into id
+				 group id by id into g
+				 select g.Max()),
+				(from ch in db.Child
+				 select ch.ChildID into id
+				 group id by id into g
+				 select g.Max())));
+		}
+
+		[Test]
+		public void Scalar2()
+		{
+			ForEachProvider(new[] { ProviderName.SqlCe }, db => AreEqual(
+				(from ch in Child
+				 group ch by ch.ParentID into g
+				 select new
+					 {
+						 Max1 = g.Select(ch => ch.ChildID              ).Max(),
+						 Max2 = g.Select(ch => ch.ChildID + ch.ParentID).Max()
+					 }),
+				(from ch in db.Child
+				 group ch by ch.ParentID into g
+				 select new
+					 {
+						 Max1 = g.Select(ch => ch.ChildID              ).Max(),
+						 Max2 = g.Select(ch => ch.ChildID + ch.ParentID).Max()
+					 })));
+		}
+
+		[Test]
+		public void Scalar3()
+		{
+			ForEachProvider(
+				new[] { ProviderName.SqlCe },
+				db => AreEqual(
+					(from ch in Child
+					 group ch by ch.ParentID into g
+					 select g.Select(ch => ch.ChildID).Where(id => id > 0).Max()),
+					(from ch in db.Child
+					 group ch by ch.ParentID into g
+					 select g.Select(ch => ch.ChildID).Where(id => id > 0).Max())));
+		}
+
+		[Test]
+		public void Scalar4()
+		{
+			ForEachProvider(
+				new[] { ProviderName.SqlCe, ProviderName.Access, ProviderName.Informix },
+				db => AreEqual(
+					from ch in Child
+					group ch by ch.ParentID into g
+					where g.Where(ch => ch.ParentID > 2).Select(ch => (int?)ch.ChildID).Min() != null
+					select g.Where(ch => ch.ParentID > 2).Select(ch => ch.ChildID).Min()
+					,
+					from ch in db.Child
+					group ch by ch.ParentID into g
+					where g.Where(ch => ch.ParentID > 2).Select(ch => (int?)ch.ChildID).Min() != null
+					select g.Where(ch => ch.ParentID > 2).Select(ch => ch.ChildID).Min()));
+		}
+
+		[Test]
+		public void Scalar41()
+		{
+			ForEachProvider(
+				new[] { ProviderName.SqlCe, ProviderName.Access, ProviderName.Informix },
+				db => AreEqual(
+					from ch in Child
+					group ch by ch.ParentID into g
+					select new { g } into g
+					where g.g.Where(ch => ch.ParentID > 2).Select(ch => (int?)ch.ChildID).Min() != null
+					select g.g.Where(ch => ch.ParentID > 2).Select(ch => ch.ChildID).Min()
+					,
+					from ch in db.Child
+					group ch by ch.ParentID into g
+					select new { g } into g
+					where g.g.Where(ch => ch.ParentID > 2).Select(ch => (int?)ch.ChildID).Min() != null
+					select g.g.Where(ch => ch.ParentID > 2).Select(ch => ch.ChildID).Min()));
+		}
+
+		[Test]
+		public void Scalar5()
+		{
+			ForEachProvider(db => AreEqual(
+				from ch in Child
+				select ch.ParentID into id
+				group id by id into g
+				select g.Max()
+				,
+				from ch in db.Child
+				select ch.ParentID into id
+				group id by id into g
+				select g.Max()));
+		}
+
+		//[Test]
+		public void Scalar51()
+		{
+			ForEachProvider(db => AreEqual(
+				from ch in Child
+				group ch by ch.ParentID into g
+				select g.Max()
+				,
+				from ch in db.Child
+				group ch by ch.ParentID into g
+				select g.Max()));
+		}
+
+		[Test]
+		public void Scalar6()
+		{
+			ForEachProvider(new[] { ProviderName.SqlCe }, db => AreEqual(
+				(from ch in Child
+				 where ch.ParentID < 3
+				 group ch by ch.ParentID into g
+				 select g.Where(ch => ch.ParentID < 3).Max(ch => ch.ChildID)),
+				(from ch in db.Child
+				 where ch.ParentID < 3
+				 group ch by ch.ParentID into g
+				 select g.Where(ch => ch.ParentID < 3).Max(ch => ch.ChildID))));
+		}
+
+		[Test]
+		public void Scalar7()
+		{
+			ForEachProvider(new[] { ProviderName.SqlCe }, db => AreEqual(
+				(from ch in Child
+				 group ch by ch.ParentID into g
+				 select new { max = g.Select(ch => ch.ChildID).Max()}).Select(id => id.max),
+				(from ch in db.Child
+				 group ch by ch.ParentID into g
+				 select new { max = g.Select(ch => ch.ChildID).Max()}).Select(id => id.max)));
+		}
+
+		[Test]
+		public void Scalar8()
+		{
+			ForEachProvider(db => AreEqual(
+				(from ch in Child
+				group ch by ch.ParentID into g
+				select new { max = g.Max(ch => ch.ChildID)}).Select(id => id.max),
+				(from ch in db.Child
+				group ch by ch.ParentID into g
+				select new { max = g.Max(ch => ch.ChildID)}).Select(id => id.max)));
+		}
+
+		[Test]
+		public void Scalar9()
+		{
+			ForEachProvider(new[] { ProviderName.SqlCe }, db => AreEqual(
+				(from ch in Child
+				 group ch by ch.ParentID into g
+				 select g.Select(ch => ch.ChildID).Where(id => id < 30).Count()),
+				(from ch in db.Child
+				 group ch by ch.ParentID into g
+				 select g.Select(ch => ch.ChildID).Where(id => id < 30).Count())));
+		}
+
+		[Test]
+		public void Scalar10()
+		{
+			ForEachProvider(new[] { ProviderName.SqlCe }, db => AreEqual(
+				(from ch in Child
+				 group ch by ch.ParentID into g
+				 select g.Select(ch => ch.ChildID).Where(id => id < 30).Count(id => id >= 20)),
+				(from ch in db.Child
+				 group ch by ch.ParentID into g
+				 select g.Select(ch => ch.ChildID).Where(id => id < 30).Count(id => id >= 20))));
+		}
+
+		[Test, Category("MySql")]
+		public void GroupByExtraFieldBugTest([IncludeDataContexts(ProviderName.MySql)] string context)
+		{
+			// https://github.com/igor-tkachev/bltoolkit/issues/42
+			// extra field is generated in the GROUP BY clause, for example:
+			// GROUP BY p.LastName, p.LastName <--- the second one is redundant
+
+			using (var db = new TestDbManager(context))
+			{
+				var q =
+					from d in db.Doctor
+					join p in db.Person on d.PersonID equals p.ID
+					group d by p.LastName into g
+					select g.Key;
+
+				q.ToList();
+
+				const string fieldName = "LastName";
+
+				var lastQuery  = db.LastQuery;
+				var groupByPos = lastQuery.IndexOf("GROUP BY");
+				var fieldPos   = lastQuery.IndexOf(fieldName, groupByPos);
+				
+				// check that our field does not present in the GROUP BY clause second time
+				Assert.AreEqual(-1, lastQuery.IndexOf(fieldName, fieldPos + 1));
+			}
+		}
+
+		[Test]
+		public void DoubleGroupBy1()
+		{
+			ForEachProvider(
+				db => AreEqual(
+					from t in
+						from p in Parent
+						where p.Value1 != null
+						group p by p.ParentID into g
+						select new
+						{
+							ID  = g.Key,
+							Max = g.Max(t => t.Value1)
+						}
+					group t by t.ID into g
+					select new
+					{
+						g.Key,
+						Sum = g.Sum(t => t.Max)
+					},
+					from t in
+						from p in db.Parent
+						where p.Value1 != null
+						group p by p.ParentID into g
+						select new
+						{
+							ID  = g.Key,
+							Max = g.Max(t => t.Value1)
+						}
+					group t by t.ID into g
+					select new
+					{
+						g.Key,
+						Sum = g.Sum(t => t.Max)
+					}));
+			
+		}
+
+		[Test]
+		public void DoubleGroupBy2()
+		{
+			ForEachProvider(
+				db => AreEqual(
+					from p in Parent
+					where p.Value1 != null
+					group p by p.ParentID into g
+					select new
+					{
+						ID  = g.Key,
+						Max = g.Max(t => t.Value1)
+					} into t
+					group t by t.ID into g
+					select new
+					{
+						g.Key,
+						Sum = g.Sum(t => t.Max)
+					},
+					from p in db.Parent
+					where p.Value1 != null
+					group p by p.ParentID into g
+					select new
+					{
+						ID  = g.Key,
+						Max = g.Max(t => t.Value1)
+					} into t
+					group t by t.ID into g
+					select new
+					{
+						g.Key,
+						Sum = g.Sum(t => t.Max)
+					}));
+			
+		}
+
+		[Test]
+		public void InnerQuery([DataContexts(ProviderName.SqlCe)] string context)
+		{
+			using (var db = GetDataContext(context))
+			{
+				AreEqual(
+					   Doctor.GroupBy(s => s.PersonID).Select(s => s.Select(d => d.Taxonomy).First()),
+					db.Doctor.GroupBy(s => s.PersonID).Select(s => s.Select(d => d.Taxonomy).First()));
+			}
+		}
+
+		[Test]
+		public void CalcMember([DataContexts] string context)
+		{
+			using (var db = GetDataContext(context))
+			{
+				AreEqual(
+					from parent in Parent
+					from child  in Person
+					where child.ID == parent.ParentID
+					let data = new
+					{
+						parent.Value1,
+						Value = child.FirstName == "John" ? child.FirstName : "a"
+					}
+					group data by data.Value into groupedData
+					select new
+					{
+						groupedData.Key,
+						Count = groupedData.Count()
+					},
+					from parent in db.Parent
+					from child  in db.Person
+					where child.ID == parent.ParentID
+					let data = new
+					{
+						parent.Value1,
+						Value = child.FirstName == "John" ? child.FirstName : "a"
+					}
+					group data by data.Value into groupedData
+					select new
+					{
+						groupedData.Key,
+						Count = groupedData.Count()
+					});
+			}
+		}
+
+		[Test]
+		public void GroupByDate([DataContexts] string context)
+		{
+			using (var db = GetDataContext(context))
+			{
+				AreEqual(
+					from t in Types2
+					group t by new { t.DateTimeValue.Value.Month, t.DateTimeValue.Value.Year } into grp
+					select new
+					{
+						Total = grp.Sum(_ => _.MoneyValue),
+						year  = grp.Key.Year,
+						month = grp.Key.Month
+					},
+					from t in db.Types2
+					group t by new { t.DateTimeValue.Value.Month, t.DateTimeValue.Value.Year } into grp
+					select new
+					{
+						Total = grp.Sum(_ => _.MoneyValue),
+						year  = grp.Key.Year,
+						month = grp.Key.Month
+					});
+			}
+		}
+	}
+}