@@ -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 ( )
@@ -1072,6 +1147,28 @@ join c in db.Customers on
1072
1147
}
1073
1148
}
1074
1149
1150
+ [ Category ( "JOIN" ) ]
1151
+ [ TestCase ( Description = "This sample explictly joins two tables with a composite key and projects results from both tables." ) ]
1152
+ public async Task DLinqJoin5fLeftJoinAsync ( )
1153
+ {
1154
+ var q =
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 } ;
1161
+
1162
+ using ( var sqlSpy = new SqlLogSpy ( ) )
1163
+ {
1164
+ await ( ObjectDumper . WriteAsync ( q ) ) ;
1165
+
1166
+ var sql = sqlSpy . GetWholeLog ( ) ;
1167
+ Assert . That ( GetTotalOccurrences ( sql , "left outer join" ) , Is . EqualTo ( 2 ) ) ;
1168
+ Assert . That ( GetTotalOccurrences ( sql , "inner join" ) , Is . EqualTo ( 0 ) ) ;
1169
+ }
1170
+ }
1171
+
1075
1172
[ Category ( "JOIN" ) ]
1076
1173
[ Test ( Description = "This sample explictly joins three tables and projects results from each of them." ) ]
1077
1174
public async Task DLinqJoin6Async ( )
@@ -1094,6 +1191,28 @@ join e in db.Employees on c.Address.City equals e.Address.City into emps
1094
1191
}
1095
1192
}
1096
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
+
1097
1216
[ Category ( "JOIN" ) ]
1098
1217
[ Test ( Description = "This sample projects a 'let' expression resulting from a join." ) ]
1099
1218
public async Task DLinqJoin8Async ( )
@@ -1158,6 +1277,51 @@ from d in details
1158
1277
Assert . AreEqual ( expected . Count , actual . Count ) ;
1159
1278
}
1160
1279
1280
+ [ Category ( "JOIN" ) ]
1281
+ [ TestCase ( true , Description = "This sample shows a group left join with a composite key." ) ]
1282
+ [ TestCase ( false , Description = "This sample shows a group left join with a composite key." ) ]
1283
+ public async Task DLinqJoin9LeftJoinAsync ( bool useCrossJoin )
1284
+ {
1285
+ if ( useCrossJoin && ! Dialect . SupportsCrossJoin )
1286
+ {
1287
+ Assert . Ignore ( "Dialect does not support cross join." ) ;
1288
+ }
1289
+
1290
+ ICollection expected , actual ;
1291
+ expected =
1292
+ ( from o in db . Orders . ToList ( )
1293
+ from p in db . Products . ToList ( )
1294
+ join d in db . OrderLines . ToList ( )
1295
+ on new { o . OrderId , p . ProductId } equals new { d . Order . OrderId , d . Product . ProductId }
1296
+ into details
1297
+ from d in details . DefaultIfEmpty ( )
1298
+ where d != null && d . UnitPrice > 50
1299
+ select new { o . OrderId , p . ProductId , d . UnitPrice } ) . ToList ( ) ;
1300
+
1301
+ using ( var substitute = SubstituteDialect ( ) )
1302
+ using ( var sqlSpy = new SqlLogSpy ( ) )
1303
+ {
1304
+ ClearQueryPlanCache ( ) ;
1305
+ substitute . Value . SupportsCrossJoin . Returns ( useCrossJoin ) ;
1306
+
1307
+ actual =
1308
+ await ( ( from o in db . Orders
1309
+ from p in db . Products
1310
+ join d in db . OrderLines
1311
+ on new { o . OrderId , p . ProductId } equals new { d . Order . OrderId , d . Product . ProductId }
1312
+ into details
1313
+ from d in details . DefaultIfEmpty ( )
1314
+ where d != null && d . UnitPrice > 50
1315
+ select new { o . OrderId , p . ProductId , d . UnitPrice } ) . ToListAsync ( ) ) ;
1316
+
1317
+ var sql = sqlSpy . GetWholeLog ( ) ;
1318
+ Assert . That ( sql , Does . Contain ( useCrossJoin ? "cross join" : "inner join" ) ) ;
1319
+ Assert . That ( GetTotalOccurrences ( sql , "left outer join" ) , Is . EqualTo ( 1 ) ) ;
1320
+ }
1321
+
1322
+ Assert . AreEqual ( expected . Count , actual . Count ) ;
1323
+ }
1324
+
1161
1325
[ Category ( "JOIN" ) ]
1162
1326
[ Test ( Description = "This sample shows a join which is then grouped" ) ]
1163
1327
public async Task DLinqJoin9bAsync ( )
@@ -1188,5 +1352,26 @@ join s2 in db.Employees on s.Superior.EmployeeId equals s2.EmployeeId
1188
1352
Assert . That ( GetTotalOccurrences ( sql , "inner join" ) , Is . EqualTo ( 2 ) ) ;
1189
1353
}
1190
1354
}
1355
+
1356
+ [ Category ( "JOIN" ) ]
1357
+ [ Test ( Description = "This sample shows how to join multiple tables using a left join." ) ]
1358
+ public async Task DLinqJoin10aLeftJoinAsync ( )
1359
+ {
1360
+ var q =
1361
+ from e in db . Employees
1362
+ join s in db . Employees on e . Superior . EmployeeId equals s . EmployeeId into sup
1363
+ from s in sup . DefaultIfEmpty ( )
1364
+ join s2 in db . Employees on s . Superior . EmployeeId equals s2 . EmployeeId into sup2
1365
+ from s2 in sup2 . DefaultIfEmpty ( )
1366
+ select new { e . FirstName , SuperiorName = s . FirstName , Superior2Name = s2 . FirstName } ;
1367
+
1368
+ using ( var sqlSpy = new SqlLogSpy ( ) )
1369
+ {
1370
+ await ( ObjectDumper . WriteAsync ( q ) ) ;
1371
+
1372
+ var sql = sqlSpy . GetWholeLog ( ) ;
1373
+ Assert . That ( GetTotalOccurrences ( sql , "left outer join" ) , Is . EqualTo ( 2 ) ) ;
1374
+ }
1375
+ }
1191
1376
}
1192
1377
}
0 commit comments