Entity framework LINQ对实体:对一对多关系进行计数

Entity framework LINQ对实体:对一对多关系进行计数,entity-framework,linq-to-entities,Entity Framework,Linq To Entities,我有几个表,其中有一对多的关系。假设我有一个Country表、一个带有FK到Country的State表和一个带有FK到State的City表 我希望能够为给定国家创建所有城市的计数,以及基于过滤器的城市计数-类似于: foreach( var country in Model.Country ) { total = country.State.All().City.All().Count() ; filtered = country.State.All().City.Any(c

我有几个表,其中有一对多的关系。假设我有一个Country表、一个带有FK到Country的State表和一个带有FK到State的City表

我希望能够为给定国家创建所有城市的计数,以及基于过滤器的城市计数-类似于:

foreach( var country in Model.Country ) {
    total = country.State.All().City.All().Count() ;
    filtered = country.State.All().City.Any(c=>c.field == value).Count();
}
显然,这是行不通的——有没有办法做到这一点

更新:

我可以遍历对象:

    foreach (var item in Model ) {

      ... other stuff in here ...

      int tot = 0;
      int filtered = 0;
      foreach (var state in item.State)
      {
        foreach (var city in state.City)
        {
          tot++;
          if (city.Field == somevalue)
            filtered ++;
        }
      }

      ... other stuff in here ...

    }
但这似乎不太优雅

更新:@AD有一些建议,但解决问题的方法是:

int tot = item.States.Sum(s=>s.City.Count);
int filtered = item.States.Sum(s=>s.City.Where(c=>c.Field == somevalue).Count());

必须在实体框架中显式加载子对象。如果你把所有的孩子都装进去,你就可以得到很好的计数

IEnumberable<Country> countries = Model.Country.Include("State");
total = countries[i].State.Count();

你为什么不把它倒过来

foreach( var country in Model.Country ) {
    var city  = Model.State.Where(x=>x.StateID==country.State.StateID).Select(x=>City)
    total  = city.Count();
    filtered = city.All(c=>c.field == value).Count();
}

您可以尝试,假设已经填充了givenCountry和value变量:

int total = EntityModel.CitySet.Where( it => it.State.Country.ID == givenCountry.ID ).Count();
在上面,您将获取整个城市集(EntityMode.CitySet)。此集合包含所有国家所有州的所有城市。问题变成了:这些城市中的哪一个子集位于“givenCountry”国家?要解决这个问题,可以将Where()应用于整个集合,然后比较国家id,看看它们是否相同。但是,由于城市只知道它所在的州(而不是国家),因此首先必须引用它所在的州(it.state)。State引用State对象,该对象具有将引用该国家的Country属性。然后it.State.Country引用“it”所在的国家和“it”所在的城市,从而在城市和国家之间建立联系

请注意,您也可以使用相反的方法来完成此操作

int total = givenCountry.Sum( c => c.States.Sum( s.Cities.Count() ) )
但是,这里您必须确保givenCountry在内存中加载了其States集合,并且每个州都加载了其Cities集合。这是因为第一个示例中的情况是在加载的对象上使用Linq to实体,而不是在实体框架实例对象上使用Linq to实体。有一种方法可以手工创建最后一个查询以使用实体框架对象,但是:

int total = EntityModel.CountrySet.Where( c => c.ID == givenCountry.ID ).Sum( c => c.States.Sum( s.Cities.Count() ) )
对于具有特定字段的城市数,您可以通过Where()调用采用类似的方法:


我的模型加载了所有的对象-我正在遍历它们并显示详细信息,但是我想要一些统计(“4/7城市在..”)类型的东西。如果它完全加载了,就嵌套你的循环,遍历每个状态而不是执行状态。all()我刚刚更新了我的问题,以显示迭代是如何工作的。不过,它似乎有点不优雅。问题是linq到实体的工作方式不是这样的。我的模型是一个国家的集合,一个国家没有城市财产——它有一个国家的集合,每个国家都有一个城市的集合。如果一个国家有一个国家的集合,那么反过来说,这个国家有一个它附属的国家。州和城市也是如此。所以,这意味着从一个城市,你可以到州,然后到国家。当然,这是假设您使用的是实体框架,并且您使用的是实体关系(从DB中的外键构建或从模型查看器手动构建)。如果您手动或从其他模型提供程序生成国家/州/城市对象,则关系将取决于您需要向我们提供的模型。使用EF和asp.net MVC 1.0。模型包含IEnemurable,并且存在关系。你的解决方案的问题是,国家没有城市导航属性,只是一个州的集合。是的,的确,国家只有一个州的列表,但该州列表允许你访问城市。这在关系中是有效的。我相信我理解我的回答中哪一部分让你困惑。我将对它进行编辑以澄清。其中关于反面的部分正是我想要的。谢谢
int total = EntityModel.CountrySet.Where( c => c.ID == givenCountry.ID ).Sum( c => c.States.Sum( s.Cities.Count() ) )
int filtered = EntityModel.CitySet.Where( it => it.field == value ).Count();