I've got a strange problem regarding linq-to-sql, and i've really tried search around for it. Im designing a sql database and where have just recently tried to retrieve an object from it.
The problem is with multiple joins. All my tables use identity-columns as primary keys.
Db designed as followed:
MasterTable : Id (primary key, identity column, int), MasterColumn1 (nvarchar(50))
Slave1: Id (primary key, identity column, int), MasterId (int, primary key -> MasterTable Id), SlaveCol1
Slave2: Id (primary key, identity column, int), MasterId (int, primary key -> MasterTable Id), SlaveColumn2
code used:
var db = new TestDbDataContext() { Log = Console.Out };
var res = from f in db.MasterTables
where f.MasterColumn1 == "wtf"
select new
{
f.Id,
SlaveCols1 = f.Slave1s.Select(s => s.SlaveCol1),
SlaveCols2 = f.Slave2s.Select(s => s.SlaveColumn2)
};
foreach (var re in res)
{
Console.Out.WriteLine(
re.Id + " "
+ string.Join(", ", re.SlaveCols1.ToArray()) + " "
+ string.Join(", ", re.SlaveCols2.ToArray())
);
}
And the log is:
SELECT [t0].[Id], [t1].[SlaveCol1], (
SELECT COUNT(*)
FROM [FR].[Slave1] AS [t2]
WHERE [t2].[MasterId] = [t0].[Id]
) AS [value]
FROM [FR].[MasterTable] AS [t0]
LEFT OUTER JOIN [FR].[Slave1] AS [t1] ON [t1].[MasterId] = [t0].[Id]
WHERE [t0].[MasterColumn1] = @p0
ORDER BY [t0].[Id], [t1].[Id]
-- @p0: Input NVarChar (Size = 3; Prec = 0; Scale = 0) [wtf]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 3.5.30729.5420
SELECT [t0].[SlaveColumn2]
FROM [FR].[Slave2] AS [t0]
WHERE [t0].[MasterId] = @x1
-- @x1: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 3.5.30729.5420
1 SlaveCol1Wtf SlaveCol2Wtf
Why oh why does it not do two outer joins instead? I really care about this because I have a much larger db with many tables referring to the one and the same table (all have one-to-many relation) and having 20 selects round-trips to databaseserver is not optimal!
As i side-note. I can produce wanted result by using explicit outer-joins like so:
var db = new TestDbDataContext() { Log = Console.Out };
var res = from f in db.MasterTables
join s1 in db.Slave1s on f.Id equals s1.MasterId into s1Tbl
from s1 in s1Tbl.DefaultIfEmpty()
join s2 in db.Slave2s on f.Id equals s2.MasterId into s2Tbl
from s2 in s2Tbl.DefaultIfEmpty()
where f.MasterColumn1 == "wtf"
select new { f.Id, s1.SlaveCol1, s2.SlaveColumn2 };
foreach (var re in res)
{
Console.Out.WriteLine(re.Id + " " + re.SlaveCol1 + " " + re.SlaveColumn2);
}
But i want to use the references Linq-To-Sql provides and not manual joins! How?
----------- edit -----------------
I've also tried prefetching like this:
using (new DbConnectionScope())
{
var db = new TestDbDataContext() { Log = Console.Out };
DataLoadOptions loadOptions = new DataLoadOptions();
loadOptions.LoadWith<MasterTable>(c => c.Slave1s);
loadOptions.LoadWith<MasterTable>(c => c.Slave2s);
db.LoadOptions = loadOptions;
var res = from f in db.MasterTables
where f.MasterColumn1 == "wtf"
select f;
foreach (var re in res)
{
Console.Out.WriteLine(re.Id + " " +
string.Join(", ", re.Slave1s.Select(s => s.SlaveCol1).ToArray()) + " " +
string.Join(", ", re.Slave2s.Select(s => s.SlaveColumn2).ToArray()));
}
}
same result =(