Skip to content

Commit 6999436

Browse files
gliljasmaca88
andauthored
Add more left join support (#2737)
And fix aggregated queries fix #2738 fix #2672 Co-authored-by: maca88 <bostjan.markezic@siol.net>
1 parent 4d3248e commit 6999436

File tree

6 files changed

+417
-50
lines changed

6 files changed

+417
-50
lines changed

src/NHibernate.Test/Async/Linq/ByMethod/JoinTests.cs

Lines changed: 154 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,7 @@
88
//------------------------------------------------------------------------------
99

1010

11-
using System;
1211
using System.Linq;
13-
using System.Reflection;
14-
using NHibernate.Cfg;
15-
using NHibernate.Engine.Query;
1612
using NHibernate.Linq;
1713
using NHibernate.Util;
1814
using NSubstitute;
@@ -21,6 +17,7 @@
2117
namespace NHibernate.Test.Linq.ByMethod
2218
{
2319
using System.Threading.Tasks;
20+
using System.Threading;
2421
[TestFixture]
2522
public class JoinTestsAsync : LinqTestCase
2623
{
@@ -114,6 +111,159 @@ public async Task LeftJoinExtensionMethodWithMultipleKeyPropertiesAsync()
114111
}
115112
}
116113

114+
[Test]
115+
public async Task LeftJoinExtensionMethodWithOuterReferenceInWhereClauseOnlyAsync()
116+
{
117+
using (var sqlSpy = new SqlLogSpy())
118+
{
119+
var animals = await (db.Animals
120+
.LeftJoin(
121+
db.Mammals,
122+
x => x.Id,
123+
x => x.Id,
124+
(animal, mammal) => new { animal, mammal })
125+
.Where(x => x.mammal.SerialNumber.StartsWith("9"))
126+
.Select(x => new { SerialNumber = x.animal.SerialNumber })
127+
.ToListAsync());
128+
129+
var sql = sqlSpy.GetWholeLog();
130+
Assert.That(animals.Count, Is.EqualTo(1));
131+
Assert.That(GetTotalOccurrences(sql, "left outer join"), Is.EqualTo(1));
132+
}
133+
}
134+
135+
[Test]
136+
public async Task LeftJoinExtensionMethodWithOuterReferenceInWhereClauseOnlyCountAsync()
137+
{
138+
using (var sqlSpy = new SqlLogSpy())
139+
{
140+
var total = await (db.Orders
141+
.LeftJoin(
142+
db.OrderLines,
143+
x => x,
144+
x => x.Order,
145+
(order, line) => new { order, line })
146+
147+
.Select(x => new { x.order.OrderId, x.line.Discount })
148+
.CountAsync());
149+
var sql = sqlSpy.GetWholeLog();
150+
Assert.That(total, Is.EqualTo(2155));
151+
Assert.That(GetTotalOccurrences(sql, "left outer join"), Is.EqualTo(1));
152+
}
153+
}
154+
155+
[KnownBug("GH-2739")]
156+
public async Task NestedLeftJoinExtensionMethodWithOuterReferenceInWhereClauseOnlyAsync(CancellationToken cancellationToken = default(CancellationToken))
157+
{
158+
using (var sqlSpy = new SqlLogSpy())
159+
{
160+
var innerAnimals = db.Animals
161+
.LeftJoin(
162+
db.Mammals,
163+
x => x.Id,
164+
x => x.Id,
165+
(animal, mammal) => new { animal, mammal })
166+
.Where(x => x.mammal.SerialNumber.StartsWith("9"))
167+
.Select(x=>x.animal);
168+
169+
var animals = await (db.Animals
170+
.LeftJoin(
171+
innerAnimals,
172+
x => x.Id,
173+
x => x.Id,
174+
(animal, animal2) => new { animal, animal2 })
175+
.Select(x => new { SerialNumber = x.animal2.SerialNumber })
176+
.ToListAsync(cancellationToken));
177+
178+
var sql = sqlSpy.GetWholeLog();
179+
Assert.That(animals.Count, Is.EqualTo(1));
180+
Assert.That(GetTotalOccurrences(sql, "left outer join"), Is.EqualTo(1));
181+
}
182+
}
183+
184+
[Test]
185+
public async Task LeftJoinExtensionMethodWithNoUseOfOuterReferenceAsync()
186+
{
187+
using (var sqlSpy = new SqlLogSpy())
188+
{
189+
var animals = await (db.Animals
190+
.LeftJoin(
191+
db.Mammals,
192+
x => x.Id,
193+
x => x.Id,
194+
(animal, mammal) => new { animal, mammal })
195+
.Select(x => x.animal)
196+
.ToListAsync());
197+
198+
var sql = sqlSpy.GetWholeLog();
199+
Assert.That(animals.Count, Is.EqualTo(6));
200+
Assert.That(GetTotalOccurrences(sql, "left outer join"), Is.EqualTo(6));
201+
}
202+
}
203+
204+
[Test]
205+
public async Task LeftJoinExtensionMethodWithNoUseOfOuterReferenceCountAsync()
206+
{
207+
using (var sqlSpy = new SqlLogSpy())
208+
{
209+
var total = await (db.Animals
210+
.LeftJoin(
211+
db.Mammals,
212+
x => x.Id,
213+
x => x.Id,
214+
(animal, mammal) => new {animal, mammal})
215+
.Select(x => x.animal)
216+
.CountAsync());
217+
218+
var sql = sqlSpy.GetWholeLog();
219+
Assert.That(total, Is.EqualTo(6));
220+
Assert.That(GetTotalOccurrences(sql, "left outer join"), Is.EqualTo(1));
221+
}
222+
}
223+
224+
[Test]
225+
public async Task LeftJoinExtensionMethodWithOuterReferenceInOrderByClauseOnlyAsync()
226+
{
227+
using (var sqlSpy = new SqlLogSpy())
228+
{
229+
var animals = await (db.Animals
230+
.LeftJoin(
231+
db.Mammals,
232+
x => x.Id,
233+
x => x.Id,
234+
(animal, mammal) => new { animal, mammal })
235+
.OrderBy(x => x.mammal.SerialNumber ?? "z")
236+
.Select(x => new { SerialNumber = x.animal.SerialNumber })
237+
.ToListAsync());
238+
239+
var sql = sqlSpy.GetWholeLog();
240+
Assert.That(animals.Count, Is.EqualTo(6));
241+
Assert.That(animals[0].SerialNumber, Is.EqualTo("1121"));
242+
Assert.That(GetTotalOccurrences(sql, "left outer join"), Is.EqualTo(1));
243+
}
244+
}
245+
246+
[Test]
247+
public async Task LeftJoinExtensionMethodWithOuterReferenceInOrderByClauseOnlyCountAsync()
248+
{
249+
using (var sqlSpy = new SqlLogSpy())
250+
{
251+
var total = await (db.Animals
252+
.LeftJoin(
253+
db.Mammals,
254+
x => x.Id,
255+
x => x.Id,
256+
(animal, mammal) => new {animal, mammal})
257+
.OrderBy(x => x.mammal.SerialNumber ?? "z")
258+
.Select(x => new {SerialNumber = x.animal.SerialNumber})
259+
.CountAsync());
260+
261+
var sql = sqlSpy.GetWholeLog();
262+
Assert.That(total, Is.EqualTo(6));
263+
Assert.That(GetTotalOccurrences(sql, "left outer join"), Is.EqualTo(1));
264+
}
265+
}
266+
117267
[TestCase(false)]
118268
[TestCase(true)]
119269
public async Task CrossJoinWithPredicateInWhereStatementAsync(bool useCrossJoin)

src/NHibernate.Test/Linq/ByMethod/JoinTests.cs

Lines changed: 154 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
using System;
2-
using System.Linq;
3-
using System.Reflection;
4-
using NHibernate.Cfg;
5-
using NHibernate.Engine.Query;
1+
using System.Linq;
62
using NHibernate.Linq;
73
using NHibernate.Util;
84
using NSubstitute;
@@ -103,6 +99,159 @@ public void LeftJoinExtensionMethodWithMultipleKeyProperties()
10399
}
104100
}
105101

102+
[Test]
103+
public void LeftJoinExtensionMethodWithOuterReferenceInWhereClauseOnly()
104+
{
105+
using (var sqlSpy = new SqlLogSpy())
106+
{
107+
var animals = db.Animals
108+
.LeftJoin(
109+
db.Mammals,
110+
x => x.Id,
111+
x => x.Id,
112+
(animal, mammal) => new { animal, mammal })
113+
.Where(x => x.mammal.SerialNumber.StartsWith("9"))
114+
.Select(x => new { SerialNumber = x.animal.SerialNumber })
115+
.ToList();
116+
117+
var sql = sqlSpy.GetWholeLog();
118+
Assert.That(animals.Count, Is.EqualTo(1));
119+
Assert.That(GetTotalOccurrences(sql, "left outer join"), Is.EqualTo(1));
120+
}
121+
}
122+
123+
[Test]
124+
public void LeftJoinExtensionMethodWithOuterReferenceInWhereClauseOnlyCount()
125+
{
126+
using (var sqlSpy = new SqlLogSpy())
127+
{
128+
var total = db.Orders
129+
.LeftJoin(
130+
db.OrderLines,
131+
x => x,
132+
x => x.Order,
133+
(order, line) => new { order, line })
134+
135+
.Select(x => new { x.order.OrderId, x.line.Discount })
136+
.Count();
137+
var sql = sqlSpy.GetWholeLog();
138+
Assert.That(total, Is.EqualTo(2155));
139+
Assert.That(GetTotalOccurrences(sql, "left outer join"), Is.EqualTo(1));
140+
}
141+
}
142+
143+
[KnownBug("GH-2739")]
144+
public void NestedLeftJoinExtensionMethodWithOuterReferenceInWhereClauseOnly()
145+
{
146+
using (var sqlSpy = new SqlLogSpy())
147+
{
148+
var innerAnimals = db.Animals
149+
.LeftJoin(
150+
db.Mammals,
151+
x => x.Id,
152+
x => x.Id,
153+
(animal, mammal) => new { animal, mammal })
154+
.Where(x => x.mammal.SerialNumber.StartsWith("9"))
155+
.Select(x=>x.animal);
156+
157+
var animals = db.Animals
158+
.LeftJoin(
159+
innerAnimals,
160+
x => x.Id,
161+
x => x.Id,
162+
(animal, animal2) => new { animal, animal2 })
163+
.Select(x => new { SerialNumber = x.animal2.SerialNumber })
164+
.ToList();
165+
166+
var sql = sqlSpy.GetWholeLog();
167+
Assert.That(animals.Count, Is.EqualTo(1));
168+
Assert.That(GetTotalOccurrences(sql, "left outer join"), Is.EqualTo(1));
169+
}
170+
}
171+
172+
[Test]
173+
public void LeftJoinExtensionMethodWithNoUseOfOuterReference()
174+
{
175+
using (var sqlSpy = new SqlLogSpy())
176+
{
177+
var animals = db.Animals
178+
.LeftJoin(
179+
db.Mammals,
180+
x => x.Id,
181+
x => x.Id,
182+
(animal, mammal) => new { animal, mammal })
183+
.Select(x => x.animal)
184+
.ToList();
185+
186+
var sql = sqlSpy.GetWholeLog();
187+
Assert.That(animals.Count, Is.EqualTo(6));
188+
Assert.That(GetTotalOccurrences(sql, "left outer join"), Is.EqualTo(6));
189+
}
190+
}
191+
192+
[Test]
193+
public void LeftJoinExtensionMethodWithNoUseOfOuterReferenceCount()
194+
{
195+
using (var sqlSpy = new SqlLogSpy())
196+
{
197+
var total = db.Animals
198+
.LeftJoin(
199+
db.Mammals,
200+
x => x.Id,
201+
x => x.Id,
202+
(animal, mammal) => new {animal, mammal})
203+
.Select(x => x.animal)
204+
.Count();
205+
206+
var sql = sqlSpy.GetWholeLog();
207+
Assert.That(total, Is.EqualTo(6));
208+
Assert.That(GetTotalOccurrences(sql, "left outer join"), Is.EqualTo(1));
209+
}
210+
}
211+
212+
[Test]
213+
public void LeftJoinExtensionMethodWithOuterReferenceInOrderByClauseOnly()
214+
{
215+
using (var sqlSpy = new SqlLogSpy())
216+
{
217+
var animals = db.Animals
218+
.LeftJoin(
219+
db.Mammals,
220+
x => x.Id,
221+
x => x.Id,
222+
(animal, mammal) => new { animal, mammal })
223+
.OrderBy(x => x.mammal.SerialNumber ?? "z")
224+
.Select(x => new { SerialNumber = x.animal.SerialNumber })
225+
.ToList();
226+
227+
var sql = sqlSpy.GetWholeLog();
228+
Assert.That(animals.Count, Is.EqualTo(6));
229+
Assert.That(animals[0].SerialNumber, Is.EqualTo("1121"));
230+
Assert.That(GetTotalOccurrences(sql, "left outer join"), Is.EqualTo(1));
231+
}
232+
}
233+
234+
[Test]
235+
public void LeftJoinExtensionMethodWithOuterReferenceInOrderByClauseOnlyCount()
236+
{
237+
using (var sqlSpy = new SqlLogSpy())
238+
{
239+
var total = db.Animals
240+
.LeftJoin(
241+
db.Mammals,
242+
x => x.Id,
243+
x => x.Id,
244+
(animal, mammal) => new {animal, mammal})
245+
.OrderBy(x => x.mammal.SerialNumber ?? "z")
246+
.Select(x => new {SerialNumber = x.animal.SerialNumber})
247+
.Count();
248+
249+
var sql = sqlSpy.GetWholeLog();
250+
Assert.That(total, Is.EqualTo(6));
251+
Assert.That(GetTotalOccurrences(sql, "left outer join"), Is.EqualTo(1));
252+
}
253+
}
254+
106255
[TestCase(false)]
107256
[TestCase(true)]
108257
public void CrossJoinWithPredicateInWhereStatement(bool useCrossJoin)

src/NHibernate/Linq/GroupJoin/AggregatingGroupJoinRewriter.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Collections.Generic;
22
using System.Linq;
3+
using NHibernate.Linq.Visitors;
34
using Remotion.Linq;
45
using Remotion.Linq.Clauses;
56

@@ -43,6 +44,8 @@ public static void ReWrite(QueryModel model)
4344

4445
if (aggregateDetectorResults.AggregatingClauses.Count > 0)
4546
{
47+
NonAggregatingGroupJoinRewriter.RewriteGroupJoins(aggregateDetectorResults.AggregatingClauses, model);
48+
4649
// Re-write the select expression
4750
model.SelectClause.TransformExpressions(s => GroupJoinSelectClauseRewriter.ReWrite(s, aggregateDetectorResults));
4851

@@ -56,7 +59,7 @@ public static void ReWrite(QueryModel model)
5659

5760
private static IsAggregatingResults IsAggregatingGroupJoin(QueryModel model, IEnumerable<GroupJoinClause> clause)
5861
{
59-
return GroupJoinAggregateDetectionVisitor.Visit(clause, model.SelectClause.Selector);
62+
return GroupJoinAggregateDetectionQueryModelVisitor.Visit(clause, model);
6063
}
6164
}
62-
}
65+
}

0 commit comments

Comments
 (0)