У меня странная проблема с linq-to-sql, и я действительно пытался ее найти. Я разрабатываю базу данных sql и только что недавно попытался извлечь из нее объект.
Проблема в нескольких соединениях. Во всех моих таблицах в качестве первичных ключей используются идентификационные столбцы.
Db разработан следующим образом:
MasterTable: Id (первичный ключ, столбец идентификатора, целое число), MasterColumn1 (nvarchar (50))
Slave1: Id (первичный ключ, столбец идентификатора, int), MasterId (int, первичный ключ -> MasterTable Id), SlaveCol1
Slave2: Id (первичный ключ, столбец идентификатора, int), MasterId (int, первичный ключ -> MasterTable Id), SlaveColumn2
используемый код:
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())
);
}
И журнал:
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
Почему, почему вместо этого не выполняется два внешних соединения? Я действительно забочусь об этом, потому что у меня гораздо больше БД со многими таблицами, относящимися к одной и той же таблице (все они имеют отношение «один ко многим»), и наличие 20 циклов выборки на сервер базы данных не является оптимальным!
В качестве примечания. Я могу получить желаемый результат, используя явные внешние соединения, например:
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);
}
Но я хочу использовать ссылки, которые предоставляет Linq-To-Sql, а не ручные соединения! Как?
----------- редактировать -----------------
Я также пробовал такую предварительную выборку:
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()));
}
}
тот же результат = (