C# 在使用实体框架时,如何将所有可枚举项自动转换为列表?

C# 在使用实体框架时,如何将所有可枚举项自动转换为列表?,c#,asp.net,entity-framework,C#,Asp.net,Entity Framework,我的ASP.NET核心Web API(带有实体框架)中有此POST端点: [HttpPost] 公共异步任务赛后(游戏){ ... game.State=新游戏状态(); game.State.Map.Rows=game.State.Map.Rows.ToList(); ... } 然后我有两门课: public class MapRow { public int Id { get; set; } public IEnumerable<MapColumn> Columns

我的ASP.NET核心Web API(带有实体框架)中有此POST端点:

[HttpPost]
公共异步任务赛后(游戏){
...
game.State=新游戏状态();
game.State.Map.Rows=game.State.Map.Rows.ToList();
...
}
然后我有两门课:

public class MapRow {

  public int Id { get; set; }
  public IEnumerable<MapColumn> Columns { get; set; }

  public MapRow() { }

  public MapRow(IEnumerable<MapColumn> columns) {
    Columns = columns;
  }
}

public class Map {

  public long Id { get; set; }
  public IEnumerable<MapRow> Rows { get; set; }

  public Map() { }

  public Map(IEnumerable<MapRow> rows) {
    Rows = rows;
  }
}
公共类映射行{
公共int Id{get;set;}
公共IEnumerable列{get;set;}
公共映射行(){}
公共映射行(IEnumerable列){
列=列;
}
}
公共类地图{
公共长Id{get;set;}
公共IEnumerable行{get;set;}
公共映射(){}
公共地图(IEnumerable行){
行=行;
}
}
其中有两个
可枚举的
s需要转换为
列表
或实体框架,将抛出类似以下错误:

System.InvalidOperationException:实体类型“MapRow”上导航属性“Columns”的类型为“SelectRangeIterator”,它不实现ICollection。集合导航属性必须实现目标类型的ICollection

我通过在端点本身中调用
.ToList()
解决了我的
行的此错误。但是,由于存在多个端点,并且可以有嵌套的
可枚举
s,因此必须手动将每个
可枚举
转换为
列表
,这很快变得无法维护


有没有一种更简单的方法可以让我实现自动化?

对于EF实体,集合的导航属性应该声明为
ICollection
,而不是
IEnumerable
。例如:

public class MapRow {

  public int Id { get; set; }
  public virtual ICollection<MapColumn> Columns { get; set; } = new List<MapColumn>();

  public MapRow() { }

  public MapRow(IEnumerable<MapColumn> columns) {
    Columns = columns;
  }
}

public class Map {

  public long Id { get; set; }
  public virtual IColleciton<MapRow> Rows { get; set; } = new List<MapRow>();

  public Map() { }

  public Map(IEnumerable<MapRow> rows) {
    Rows = rows;
  }
}
公共类映射行{
公共int Id{get;set;}
公共虚拟ICollection列{get;set;}=new List();
公共映射行(){}
公共映射行(IEnumerable列){
列=列;
}
}
公共类地图{
公共长Id{get;set;}
公共虚拟ICollection行{get;set;}=new List();
公共映射(){}
公共地图(IEnumerable行){
行=行;
}
}
ICollection
扩展了
IEnumerable
,因此任何期望IEnumerable的方法都将完全满足于ICollection。当您尝试将IEnumerable传递给期望IList或ICollection的对象时,情况就不同了


将它们声明为
virtual
还允许EF为这些属性分配代理,以便在需要时协助延迟加载,并且DbContext仍然可用。它还有助于自动初始化新集合的属性,以便在新建映射时,您可以立即开始添加行和列,而不会出现
NullReferenceException
s.

您至少应该将ICollection用于导航属性。不要在公共api中使用实体类型。映射到和从他们。它可以解决这个问题以及其他一些问题(如过度发布)@pinkfloydx33你介意扩大你的评论作为回答吗?我昨天从C#开始,不知道你的意思是什么:有趣。如果我有
=newlist(),这有关系吗因为我传递了一个带有构造函数的列表?不,该构造函数将覆盖引用,尽管您仍然有一个默认构造函数,但它不可用,所以它只是作为一个总括,以确保任何新实体都准备好接受其集合中的项。嗯,好的。空构造函数的唯一原因是EF抛出错误,告诉我我需要它们,不管是什么原因我都不知道。当我可以的时候,我会测试它,如果它按预期工作,我会接受答案:)是的,EF需要能够构造实体,所以它不一定知道传递给构造函数所需的所有子状态或潜在的任意默认值。默认初始值设定项有助于使新对象保持可用状态。
public class MapRow {

  public int Id { get; set; }
  public virtual ICollection<MapColumn> Columns { get; set; } = new List<MapColumn>();

  public MapRow() { }

  public MapRow(IEnumerable<MapColumn> columns) {
    Columns = columns;
  }
}

public class Map {

  public long Id { get; set; }
  public virtual IColleciton<MapRow> Rows { get; set; } = new List<MapRow>();

  public Map() { }

  public Map(IEnumerable<MapRow> rows) {
    Rows = rows;
  }
}