有没有办法重写这个LINQ查询,以便它只进行一次SQL查询?

时间:2009-07-28 07:19:06

标签: linq-to-sql optimization

我有一个LINQ查询,它获取嵌套对象列表。

from c in ClientsRepository.LoadAll()
orderby c.Name
select new ComboBoxOptionGroup
    {
    Text = c.Name,
    Options = from p in c.Projects
              orderby p.Name
              select new ComboBoxOption
              {
                  Text = p.Name,
                  Value = p.ID.ToString()
              }
    } 

不幸的是,这个LINQ查询导致num(客户端)+1 SQL查询。有没有任何优雅的方法来重写它,以便它只导致一个SQL查询?

我的想法是获取客户订购的所有项目,并在两个嵌套的foreach循环中完成剩下的工作,但这似乎违背了LINQ设计时的优雅。还有更好的选择吗?

3 个答案:

答案 0 :(得分:2)

如果ClientsRepository.LoadAll()是查询的包装器,它实际上会进入数据库并检索数据(不返回IQueryable<T>),那么就会被卡住。如果它返回一个查询的一部分(确实返回IQueryable<T>)那么它应该是可能的。

但是,如果不知道数据(或对象)上下文的位置和模型,则很难。

通常情况下,我希望做类似的事情:

from client in dataContext.Clients
join p in dataContext.Projects on p.ClientId equals c.Id
  into projects
orderby client.Name
select new ComboBoxOptionGroup {
  Text = client.Name,
  Option = from p in projects
           orderby p.Name
           select new ComboBoxOption {
             Text = p.Name,
             Value = p.ID.ToString()
           }
}

答案 1 :(得分:2)

另一种可能的替代方法是使用DataLoadOptions

DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Client>(c => c.Projects);
context.DeferredLoadingEnabled = false; // You may not need/want this line
context.LoadOptions = dlo;

我没有测试过这种做法,但您希望能够单独留下查询并减少必要查询的数量。

答案 2 :(得分:1)

您可能会搜索“加入”运算符:http://www.hookedonlinq.com/JoinOperator.ashx