Take care of performance:
I experienced that at least with EF Core the different answers given here might result in different performance. I'm aware that the OP asked about Linq to SQL, but it seems to me that the same questions occur also with EF Core.
In a specific case I had to handle, the (syntactically nicer) suggestion by Marc Gravell resulted in left joins inside a cross apply -- similarly to what Mike U described -- which had the result that the estimated costs for this specific query were two times as high compared to a query with no cross joins. The server execution times differed by a factor of 3. [1]
The solution by Marc Gravell resulted in a query without cross joins.
Context: I essentially needed to perform two left joins on two tables each of which again required a join to another table. Furthermore, there I had to specify other where-conditions on the tables on which I needed to apply the left join.
In addition, I had two inner joins on the main table.
Estimated operator costs:
- with cross apply: 0.2534
- without cross apply: 0.0991.
Server execution times in ms (queries executed 10 times; measured using SET STATISTICS TIME ON):
- with cross apply: 5, 6, 6, 6, 6, 6, 6, 6, 6, 6
- without cross apply: 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
(The very first run was slower for both queries; seems that something is cached.)
Table sizes:
- main table: 87 rows,
- first table for left join: 179 rows;
- second table for left join: 7 rows.
EF Core version: 2.2.1.
SQL Server version:
MS SQL Server 2017 - 14... (on Windows 10).
All relevant tables had indexes on the primary keys only.
My conclusion: it's always recommended to look at the generated SQL since it can really differ.
[1] Interestingly enough, when setting the 'Client statistics' in MS SQL Server Management Studio on, I could see an opposite trend; namely that last run of the solution without cross apply took more than 1s. I suppose that something was going wrong here - maybe with my setup.