@@ -768,6 +768,26 @@ from o in c.Orders
768
768
}
769
769
}
770
770
771
+ [ Category ( "JOIN" ) ]
772
+ [ Test ( Description = "This sample uses foreign key navigation in the " +
773
+ "from clause to select all orders for customers in London." ) ]
774
+ public async Task DLinqJoin1LeftJoinAsync ( )
775
+ {
776
+ IQueryable < Order > q =
777
+ from c in db . Customers
778
+ from o in c . Orders . DefaultIfEmpty ( )
779
+ where c . Address . City == "London"
780
+ select o ;
781
+
782
+ using ( var sqlSpy = new SqlLogSpy ( ) )
783
+ {
784
+ await ( ObjectDumper . WriteAsync ( q ) ) ;
785
+
786
+ var sql = sqlSpy . GetWholeLog ( ) ;
787
+ Assert . That ( GetTotalOccurrences ( sql , "left outer join" ) , Is . EqualTo ( 1 ) ) ;
788
+ }
789
+ }
790
+
771
791
[ Category ( "JOIN" ) ]
772
792
[ Test ( Description = "This sample shows how to construct a join where one side is nullable and the other isn't." ) ]
773
793
public async Task DLinqJoin10Async ( )
@@ -974,6 +994,26 @@ join o in db.Orders on c.CustomerId equals o.Customer.CustomerId
974
994
}
975
995
}
976
996
997
+ [ Category ( "JOIN" ) ]
998
+ [ Test ( Description = "This sample explictly joins two tables and projects results from both tables." ) ]
999
+ public async Task DLinqJoin5aLeftJoinAsync ( )
1000
+ {
1001
+ var q =
1002
+ from c in db . Customers
1003
+ join o in db . Orders on c . CustomerId equals o . Customer . CustomerId into orders
1004
+ from o in orders . DefaultIfEmpty ( )
1005
+ where o != null
1006
+ select new { c . ContactName , o . OrderId } ;
1007
+
1008
+ using ( var sqlSpy = new SqlLogSpy ( ) )
1009
+ {
1010
+ await ( ObjectDumper . WriteAsync ( q ) ) ;
1011
+
1012
+ var sql = sqlSpy . GetWholeLog ( ) ;
1013
+ Assert . That ( GetTotalOccurrences ( sql , "left outer join" ) , Is . EqualTo ( 1 ) ) ;
1014
+ }
1015
+ }
1016
+
977
1017
[ Category ( "JOIN" ) ]
978
1018
[ Test ( Description = "This sample explictly joins two tables and projects results from both tables using a group join." ) ]
979
1019
public async Task DLinqJoin5bAsync ( )
@@ -1032,6 +1072,21 @@ join o in db.Orders on
1032
1072
}
1033
1073
}
1034
1074
1075
+ [ Category ( "JOIN" ) ]
1076
+ [ Test ( Description = "This sample explictly joins two tables with a composite key and projects results from both tables." ) ]
1077
+ public void DLinqJoin5dLeftJoinAsync ( )
1078
+ {
1079
+ var q =
1080
+ from c in db . Customers
1081
+ join o in db . Orders on
1082
+ new { c . CustomerId , HasContractTitle = c . ContactTitle != null } equals
1083
+ new { o . Customer . CustomerId , HasContractTitle = o . Customer . ContactTitle != null } into orders
1084
+ from o in orders . DefaultIfEmpty ( )
1085
+ select new { c . ContactName , o . OrderId } ;
1086
+
1087
+ Assert . ThrowsAsync < NotSupportedException > ( ( ) => ObjectDumper . WriteAsync ( q ) ) ;
1088
+ }
1089
+
1035
1090
[ Category ( "JOIN" ) ]
1036
1091
[ Test ( Description = "This sample joins two tables and projects results from the first table." ) ]
1037
1092
public async Task DLinqJoin5eAsync ( )
@@ -1051,6 +1106,26 @@ join o in db.Orders on c.CustomerId equals o.Customer.CustomerId
1051
1106
}
1052
1107
}
1053
1108
1109
+ [ Category ( "JOIN" ) ]
1110
+ [ Test ( Description = "This sample joins two tables and projects results from the first table." ) ]
1111
+ public async Task DLinqJoin5eLeftJoinAsync ( )
1112
+ {
1113
+ var q =
1114
+ from c in db . Customers
1115
+ join o in db . Orders on c . CustomerId equals o . Customer . CustomerId into orders
1116
+ from o in orders . DefaultIfEmpty ( )
1117
+ where c . ContactName != null
1118
+ select o ;
1119
+
1120
+ using ( var sqlSpy = new SqlLogSpy ( ) )
1121
+ {
1122
+ await ( ObjectDumper . WriteAsync ( q ) ) ;
1123
+
1124
+ var sql = sqlSpy . GetWholeLog ( ) ;
1125
+ Assert . That ( GetTotalOccurrences ( sql , "left outer join" ) , Is . EqualTo ( 1 ) ) ;
1126
+ }
1127
+ }
1128
+
1054
1129
[ Category ( "JOIN" ) ]
1055
1130
[ TestCase ( Description = "This sample explictly joins two tables with a composite key and projects results from both tables." ) ]
1056
1131
public async Task DLinqJoin5fAsync ( )
@@ -1073,21 +1148,24 @@ join c in db.Customers on
1073
1148
}
1074
1149
1075
1150
[ Category ( "JOIN" ) ]
1076
- [ Test ( Description = "This sample joins two tables and projects results from the first table ." ) ]
1077
- public async Task DLinqJoin5eAsync ( )
1151
+ [ TestCase ( Description = "This sample explictly joins two tables with a composite key and projects results from both tables ." ) ]
1152
+ public async Task DLinqJoin5fLeftJoinAsync ( )
1078
1153
{
1079
1154
var q =
1080
- from c in db . Customers
1081
- join o in db . Orders on c . CustomerId equals o . Customer . CustomerId
1082
- where c . ContactName != null
1083
- select o ;
1155
+ from o in db . Orders
1156
+ join c in db . Customers on
1157
+ new { o . Customer . CustomerId , HasContractTitle = o . Customer . ContactTitle != null } equals
1158
+ new { c . CustomerId , HasContractTitle = c . ContactTitle != null } into customers
1159
+ from c in customers . DefaultIfEmpty ( )
1160
+ select new { c . ContactName , o . OrderId } ;
1084
1161
1085
1162
using ( var sqlSpy = new SqlLogSpy ( ) )
1086
1163
{
1087
1164
await ( ObjectDumper . WriteAsync ( q ) ) ;
1088
1165
1089
1166
var sql = sqlSpy . GetWholeLog ( ) ;
1090
- Assert . That ( GetTotalOccurrences ( sql , "inner join" ) , Is . EqualTo ( 1 ) ) ;
1167
+ Assert . That ( GetTotalOccurrences ( sql , "left outer join" ) , Is . EqualTo ( 2 ) ) ;
1168
+ Assert . That ( GetTotalOccurrences ( sql , "inner join" ) , Is . EqualTo ( 0 ) ) ;
1091
1169
}
1092
1170
}
1093
1171
@@ -1113,6 +1191,28 @@ join e in db.Employees on c.Address.City equals e.Address.City into emps
1113
1191
}
1114
1192
}
1115
1193
1194
+ [ Category ( "JOIN" ) ]
1195
+ [ Test (
1196
+ Description =
1197
+ "This sample shows how to get LEFT OUTER JOIN by using DefaultIfEmpty(). The DefaultIfEmpty() method returns null when there is no Order for the Employee."
1198
+ ) ]
1199
+ public async Task DLinqJoin7Async ( )
1200
+ {
1201
+ var q =
1202
+ from e in db . Employees
1203
+ join o in db . Orders on e equals o . Employee into ords
1204
+ from o in ords . DefaultIfEmpty ( )
1205
+ select new { e . FirstName , e . LastName , Order = o } ;
1206
+
1207
+ using ( var sqlSpy = new SqlLogSpy ( ) )
1208
+ {
1209
+ await ( ObjectDumper . WriteAsync ( q ) ) ;
1210
+
1211
+ var sql = sqlSpy . GetWholeLog ( ) ;
1212
+ Assert . That ( GetTotalOccurrences ( sql , "left outer join" ) , Is . EqualTo ( 1 ) ) ;
1213
+ }
1214
+ }
1215
+
1116
1216
[ Category ( "JOIN" ) ]
1117
1217
[ Test ( Description = "This sample projects a 'let' expression resulting from a join." ) ]
1118
1218
public async Task DLinqJoin8Async ( )
@@ -1175,6 +1275,51 @@ from d in details
1175
1275
}
1176
1276
}
1177
1277
1278
+ [ Category ( "JOIN" ) ]
1279
+ [ TestCase ( true , Description = "This sample shows a group left join with a composite key." ) ]
1280
+ [ TestCase ( false , Description = "This sample shows a group left join with a composite key." ) ]
1281
+ public async Task DLinqJoin9LeftJoinAsync ( bool useCrossJoin )
1282
+ {
1283
+ if ( useCrossJoin && ! Dialect . SupportsCrossJoin )
1284
+ {
1285
+ Assert . Ignore ( "Dialect does not support cross join." ) ;
1286
+ }
1287
+
1288
+ ICollection expected , actual ;
1289
+ expected =
1290
+ ( from o in db . Orders . ToList ( )
1291
+ from p in db . Products . ToList ( )
1292
+ join d in db . OrderLines . ToList ( )
1293
+ on new { o . OrderId , p . ProductId } equals new { d . Order . OrderId , d . Product . ProductId }
1294
+ into details
1295
+ from d in details . DefaultIfEmpty ( )
1296
+ where d != null && d . UnitPrice > 50
1297
+ select new { o . OrderId , p . ProductId , d . UnitPrice } ) . ToList ( ) ;
1298
+
1299
+ using ( var substitute = SubstituteDialect ( ) )
1300
+ using ( var sqlSpy = new SqlLogSpy ( ) )
1301
+ {
1302
+ ClearQueryPlanCache ( ) ;
1303
+ substitute . Value . SupportsCrossJoin . Returns ( useCrossJoin ) ;
1304
+
1305
+ actual =
1306
+ await ( ( from o in db . Orders
1307
+ from p in db . Products
1308
+ join d in db . OrderLines
1309
+ on new { o . OrderId , p . ProductId } equals new { d . Order . OrderId , d . Product . ProductId }
1310
+ into details
1311
+ from d in details . DefaultIfEmpty ( )
1312
+ where d != null && d . UnitPrice > 50
1313
+ select new { o . OrderId , p . ProductId , d . UnitPrice } ) . ToListAsync ( ) ) ;
1314
+
1315
+ var sql = sqlSpy . GetWholeLog ( ) ;
1316
+ Assert . That ( sql , Does . Contain ( useCrossJoin ? "cross join" : "inner join" ) ) ;
1317
+ Assert . That ( GetTotalOccurrences ( sql , "left outer join" ) , Is . EqualTo ( 1 ) ) ;
1318
+ }
1319
+
1320
+ Assert . AreEqual ( expected . Count , actual . Count ) ;
1321
+ }
1322
+
1178
1323
[ Category ( "JOIN" ) ]
1179
1324
[ Test ( Description = "This sample shows a join which is then grouped" ) ]
1180
1325
public async Task DLinqJoin9bAsync ( )
@@ -1205,5 +1350,26 @@ join s2 in db.Employees on s.Superior.EmployeeId equals s2.EmployeeId
1205
1350
Assert . That ( GetTotalOccurrences ( sql , "inner join" ) , Is . EqualTo ( 2 ) ) ;
1206
1351
}
1207
1352
}
1353
+
1354
+ [ Category ( "JOIN" ) ]
1355
+ [ Test ( Description = "This sample shows how to join multiple tables using a left join." ) ]
1356
+ public async Task DLinqJoin10aLeftJoinAsync ( )
1357
+ {
1358
+ var q =
1359
+ from e in db . Employees
1360
+ join s in db . Employees on e . Superior . EmployeeId equals s . EmployeeId into sup
1361
+ from s in sup . DefaultIfEmpty ( )
1362
+ join s2 in db . Employees on s . Superior . EmployeeId equals s2 . EmployeeId into sup2
1363
+ from s2 in sup2 . DefaultIfEmpty ( )
1364
+ select new { e . FirstName , SuperiorName = s . FirstName , Superior2Name = s2 . FirstName } ;
1365
+
1366
+ using ( var sqlSpy = new SqlLogSpy ( ) )
1367
+ {
1368
+ await ( ObjectDumper . WriteAsync ( q ) ) ;
1369
+
1370
+ var sql = sqlSpy . GetWholeLog ( ) ;
1371
+ Assert . That ( GetTotalOccurrences ( sql , "left outer join" ) , Is . EqualTo ( 2 ) ) ;
1372
+ }
1373
+ }
1208
1374
}
1209
1375
}
0 commit comments