消除循环并使用Linq

时间:2013-09-12 15:29:34

标签: c# linq entity-framework foreach

说我有一个列表如下:

 List<R> lstR = GetR();

现在我想要一个Linq语句来将菜单分配给R,我通过使用循环然后使用Linq来获得如下菜单来实现这一点:

 List<int> ids = new List<int>();
 foreach (R r in lstR)
 {
   ids.Add(r.Id);
 }

 menu = (from s in db.Menu
         where ids.Contains(s.R.Id)
         select s.MenuText).Distinct();

据我所知,上面是两个循环(Linq正在使用内部循环)。我可以将这两个语句结合起来,即不进行第一个循环来获取ID吗?

5 个答案:

答案 0 :(得分:3)

lstRdb.Menu中都是数据库中的内存数据集(Linq-to-Objects)或IQueryable集合,您可以这样做:

menu = 
    (from s in db.Menu
     where lstR.Select(r => r.Id)
               .Contains(s.R.Id)
     select s.MenuText)
    .Distinct();

或者这个:

menu = 
    (from s in db.Menu
     join r in lstR on s.R.Id equals r.Id
     select s.MenuText)
    .Distinct();

但是,由于List<R>存在于内存中且db.MenuIQueryable,因此您的选项有限。您可以将db.Menu具体化为IEnumerable,以便在内存中处理它:

List<R> lstR = GetR();
menu = 
    (from s in db.Menu.AsEnumerable()
     join r in lstR on s.R.Id equals r.Id
     select s.MenuText)
    .Distinct();

但是,如果有大量记录,这可能会很昂贵。做这样的事情会更好,这与你已经拥有的东西没什么不同:

List<R> lstR = GetR();
var ids = lstR.Select(r => r.Id).ToList(); // or .ToArray();
menu = 
    (from s in db.Menu
     where ids.Contains(s.R.Id)
     select s.MenuText)
    .Distinct();

但实际上,最好的选择是看看你是否可以重构GetR以便从数据库中返回IQueryable<R>。这样,您可以使用前两个选项,而无需先将任何集合实现到内存中。顺便说一句,一旦你完成设置导航属性,你可以做这样的事情:

IQueryable<R> lstR = GetR();
menu = 
    (from r in lstR
     from s in r.Menus
     select s.MenuText)
    .Distinct();

答案 1 :(得分:2)

可以这样做。

menu = (from s in db.Menu
        where lstR.Select(item => item.Id).Contains(s.R.Id)
        select s.MenuText).Distinct();

但我不会将这两个语句结合起来,因为如果你使用HashSet它会加速:

var ids = new HashSet<int>(lstR);

menu = (from s in db.Menu
     where ids.Contains(s.R.Id)
     select s.MenuText).Distinct();

我想这会更快。第一个问题是,s中的每个db.Menu都会重复列表,以创建ID为select()的列表。

答案 2 :(得分:1)

您可以使用linq投影方法Select()

ids = lstR.Select(p => p.Id);

答案 3 :(得分:1)

menu = db.Menu.Where(s => GetR().Select(r => r.Id).Contains(s.R.Id))
                     .Select(s => s.MenuText)
                     .Distinct();

但它会变得复杂。如果你这样写的话会更好

        var ids = GetR().Select(r => r.Id);

        menu = db.Menu.Where(s => ids.Contains(s.R.Id))
                      .Select(s => s.MenuText)
                      .Distinct();

答案 4 :(得分:0)

使用加入

var result = (from s in db.Menu
              join r in lstR on s.Id equals r.ID
              select s.MenuText).Distinct();