LINQ to-SQL:每行返回一个"array of rows"属性(或列)



Groups的简单查询会为其每个结果生成另一个查询:

using (var db = new DataClasses1DataContext())
{
db.Log = Console.Out;
var query = from g in db.Groups
let stats = from s in g.GroupCountryStats
select new
{
s.CountryId,
s.MembersCount
}
select new
{
g.ObjectId,
g.Name,
Stats = stats.ToArray()
};
var single = query.First(); // Take(2) would result in 2 extra calls, 3 in 3 and so on...
}

控制台输出(Linq-to-Sql 提供程序日志(:

SELECT TOP (1) [t0].[ObjectId] AS [ObjectId], [t0].[Name]
FROM [dbo].[Groups] AS [t0]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.7.3056.0
SELECT [t0].[CountryId] AS [CountryId], [t0].[MembersCount]
FROM [dbo].[GroupCountryStats] AS [t0]
WHERE [t0].[GroupId] = @x1
-- @x1: Input Int (Size = -1; Prec = 0; Scale = 0) [1]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.7.3056.0
Press any key to continue . . .

我想在一个查询中检索所有数据,而不是 N+1 个查询。

我尝试使用DataLoadOptionsLoadWith<Group>(T=>T.GroupCountryStats)但结果没有变化。Linq2Sql 仍然对数据库进行 1 次以上的调用。

如何避免这种情况并在一次通话中收到我需要的一切?

这是 LINQ-to-SQL 中的一个错误(或充其量是一个缺点(。没有FirstTake的查询转换为一个包含OUTER JOIN的体面SQL查询。但当然,它会给你所有的组。

当 LINQ-to-SQL 遇到限制结果数的语句时,似乎已编程为仅将这些语句应用于根实体,然后分别查询符合实体。

有趣的是:当SkipTake结合在一起时,这种情况不会发生。因此,作为黑客,您可以使用Skip(0).take(x),例如:

var results = query.Skip(0).Take(3).ToList();

如果你需要一个结果,你必须做:

var results = query.Skip(0).Take(1).AsEnumerable().First();

如果没有.AsEnumerable()将再次陷入 1 + 1 查询。(我假设First的 SQL 翻译在查询形状中优先(。

这是一个肮脏的黑客,对于对抗IQueryable的泄漏抽象是必要的。确保,如果您选择使用它,请在代码中很好地注释它。

最后的评论:也许你应该考虑转向更高级的ORM,如实体框架。

最新更新