@@ -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 ( )
@@ -1156,6 +1275,50 @@ from d in details
1156
1275
}
1157
1276
}
1158
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
+ // The expected collection can be obtained from the below Linq to Objects query.
1289
+ //var 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
+ var 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 ( actual . Count , Is . EqualTo ( 163 ) ) ;
1317
+ Assert . That ( sql , Does . Contain ( useCrossJoin ? "cross join" : "inner join" ) ) ;
1318
+ Assert . That ( GetTotalOccurrences ( sql , "left outer join" ) , Is . EqualTo ( 1 ) ) ;
1319
+ }
1320
+ }
1321
+
1159
1322
[ Category ( "JOIN" ) ]
1160
1323
[ Test ( Description = "This sample shows a join which is then grouped" ) ]
1161
1324
public async Task DLinqJoin9bAsync ( )
@@ -1186,5 +1349,26 @@ join s2 in db.Employees on s.Superior.EmployeeId equals s2.EmployeeId
1186
1349
Assert . That ( GetTotalOccurrences ( sql , "inner join" ) , Is . EqualTo ( 2 ) ) ;
1187
1350
}
1188
1351
}
1352
+
1353
+ [ Category ( "JOIN" ) ]
1354
+ [ Test ( Description = "This sample shows how to join multiple tables using a left join." ) ]
1355
+ public async Task DLinqJoin10aLeftJoinAsync ( )
1356
+ {
1357
+ var q =
1358
+ from e in db . Employees
1359
+ join s in db . Employees on e . Superior . EmployeeId equals s . EmployeeId into sup
1360
+ from s in sup . DefaultIfEmpty ( )
1361
+ join s2 in db . Employees on s . Superior . EmployeeId equals s2 . EmployeeId into sup2
1362
+ from s2 in sup2 . DefaultIfEmpty ( )
1363
+ select new { e . FirstName , SuperiorName = s . FirstName , Superior2Name = s2 . FirstName } ;
1364
+
1365
+ using ( var sqlSpy = new SqlLogSpy ( ) )
1366
+ {
1367
+ await ( ObjectDumper . WriteAsync ( q ) ) ;
1368
+
1369
+ var sql = sqlSpy . GetWholeLog ( ) ;
1370
+ Assert . That ( GetTotalOccurrences ( sql , "left outer join" ) , Is . EqualTo ( 2 ) ) ;
1371
+ }
1372
+ }
1189
1373
}
1190
1374
}
0 commit comments