C#中的父子流利Linq查询

本文关键字:Linq 查询 父子 | 更新日期: 2023-09-27 18:02:36

我在fluent LINQ中遇到了一个问题,用于将父级和子级选择到一个Ienumerable < anonymous type>

为了简单起见:

  • 有一个commanders(每个地区的指挥官(的列表。

  • 每个指挥官都有自己的List of Soldiers。(每个Soldier都有一个布尔属性IsCanWinWar和一个他用来对抗的Tool(

我想列出每个指挥官(有一个或多个能赢得战争的士兵(该士兵使用的一个tool名称。

我不在乎一个指挥官是否有不止一个能赢得战争的士兵。

指挥官所需要的只是一名士兵(能够赢得战争(的tool(别管是哪种工具(。

输出为Ienumerable < anonymous type>,其中匿名类型类似于:

{ 
  theCommander = [commanderObject] , 
  theToolName = [the tool name ]
} 

我用selectMany做了一些事情,但它又长又丑

是否有任何短查询(fluent query(可以以更短的方式产生相同的结果?

public class Commander
    {
    public List<Soldier> lstSoldiers =new List<Soldier>(); //from db actually.
    }

    public class Soldier
    {
      public bool IsCanWinWar { get; set; }
      public string Tool { get; set; }
    }

void Main()
{
  List<Commander> lstCommanders = new List<Commander>(); //data source is actually from db.
  var MyIernumerableOfAnonymouseTypes= ?
}

C#中的父子流利Linq查询

var MyIernumerableOfAnonymouseTypes = 
   lstCommanders.Select(c => new { 
                    theCommander = c, 
                    theToolName = c.lstSoldiers.Where(s => s.IsCanWinWar)
                                               .Select(s => s.Tool)
                                               .FirstOrDefault() })
                .Where(x => x.theToolName != null);

若并没有一个士兵能够赢得战争,那个么这个工具将是无效的。只要筛选出那些指挥官。

顺便说一句,我认为Soldiers是一个更好的属性名称,而不是lstSoldiers(它没有前缀,是PascalCase(。

第一种方法(稍后修订(:

from commander in lstCommanders
where commander.lstSoldiers.Any(soldier => soldier.IsCanWinWar) // Consider only commanders who have at least one soldier who can win the war
select new
            {
                Commander = commander,
                Tool = (from soldier in commander.lstSoldiers
                        where soldier.IsCanWinWar // Consider tool originating from soldiers who can win the war
                        select soldier.Tool).FirstOrDefault()
            };

第二个更简洁、更快:

from commander in lstCommanders
where commander.lstSoldiers.Any(soldier => soldier.IsCanWinWar)
select new { Commander = commander, Tool = commander.lstSoldiers.First(soldier => soldier.IsCanWinWar).Tool };

以流畅的方式:

lstCommanders.Where(commander => commander.lstSoldiers.Any(soldier => soldier.IsCanWinWar))
             .Select(  commander => new
                                         {
                                                 Commander = commander,
                                                 Tool = commander.lstSoldiers.First(soldier => soldier.IsCanWinWar).Tool
                                         });

一次迭代的第三个选项:

from commander in lstCommanders
let winner = commander.lstSoldiers.FirstOrDefault(soldier => soldier.IsCanWinWar)
where null != winner // Consider only commanders who have at least one soldier who can win the war
select new { Commander = commander, Tool = winner.Tool };