gpt4 book ai didi

c# - Linq-to-sql 不产生多个外部连接?

转载 作者:太空狗 更新时间:2023-10-29 20:37:28 24 4
gpt4 key购买 nike

我遇到了一个关于 linq-to-sql 的奇怪问题,我真的尝试四处寻找它。我正在设计一个 sql 数据库,最近刚刚尝试从中检索一个对象。

问题在于多个连接。我的所有表都使用标识列作为主键。

Db 设计如下:

MasterTable : Id (主键, 标识列, int), 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()));
}
}

同样的结果=(

最佳答案

通过使用 LoadOptions 的预取选项并遍历关联而不是显式连接,您走在了正确的轨道上,但是由于您正在尝试从 MasterTable 进行多次 1-M 导航,因此您实际上会在两者之间创建笛卡尔积Slave1 和 Slave2 记录。因此,LINQ to SQL 会忽略您的加载选项并延迟加载每个子项的子记录。

您可以通过删除第二个子加载选项来稍微优化它。生成的查询现在将执行单个请求,返回您的 MasterTable 和 Slave1,然后延迟加载每个 Slave2。如果您执行以下操作,您应该会看到相同的结果:

var res = from f in db.MasterTables
where f.MasterColun1 == "wtf"
select new
{
f.Id,
Cols1 = f.Slave1s.Select(s => s.SlaveCol1).ToArray()
Cols2 = f.Slave2s.Select(s => s.SlaveColumn2).ToArray()
}

您应该看到 MasterTables 和 Slave1s 之间的左连接,然后延迟加载 Slave2s 以避免在 SQL 的扁平化结果中 Slave1 和 Slave2 之间的笛卡尔积。

关于c# - Linq-to-sql 不产生多个外部连接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7351746/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com