仅仅因为您在连接中指定表并不意味着您在迭代值时不会遇到 n+1 问题。考虑对您的查询进行以下扩展:
var query = from o in Orders
join c in Customers on o.CustomerID equals c.CustomerID
select o;
foreach (var o in query)
{
Console.WriteLine(String.Format("{0}: {1}", o.OrderDate, o.Employee.FirstName));
}
在这种情况下,每次您浏览订单的 Employee 对象时,都会从该订单的数据库中获取雇员。如果你想避免这个问题,你可以在 select 子句中投射你想要的值:
var query = from o in Orders
join c in Customers on o.CustomerID equals c.CustomerID
select new {o.OrderDate, o.Employee.FirstName};
foreach (var o in query)
{
Console.WriteLine(String.Format("{0}: {1}", o.OrderDate, o.FirstName));
}
请注意,在这种情况下,您甚至不需要加入,因为您只需使用导航属性即可。当然,如果您的实体中不允许导航属性并且仅依赖于连接,则可以避免 n+1 的情况,但这不是一种非常 OOP 的解决问题的方法。
如果您只从查询中返回匿名类型,我认为您可以安全地保证反对 n+1 ,但这也将是相当严格的。
最好的选择是确保对应用程序生成的 SQL 进行概要分析,并准确了解何时以及为何访问数据库。我在http://www.thinqlinq.com/Post.aspx/Title/LINQ-to-Database-Performance-hints讨论了一些可用的分析器。