cshtml运行时错误:LINQ to Entities中仅支持无参数构造函数和初始值设定项

Ger*_*ard 1 asp.net-mvc razor

想要在cshtml中使用公共类的对象,但是遇到了运行时错误:LINQ to Entities中仅支持无参数构造函数和初始值设定项.以下陈述有什么问题?谢谢你的帮助!

@foreach (var obj in ViewData["IncompleteList"] as IEnumerable<Games.TeamAction>)
Run Code Online (Sandbox Code Playgroud)

控制器填充ViewBag,就像

IEnumerable<TeamAction> incomplete = dbIncAct.IncompleteActivity.Where(a => a.activityID == id)
                                .Select(s => new TeamAction(s.teamID, s.name, id, s.type));
ViewBag.IncompleteList = incomplete;
Run Code Online (Sandbox Code Playgroud)

TeamAction类(命名空间游戏的一部分)非常简单:

public class TeamAction
{
    public TeamAction()
    {
    }

    ....

    public int teamID {get; set;}
    public string teamName { get; set; }
    public int activityID { get; set; }
    public int actionType { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

Mic*_*eld 5

一旦你弄清楚如何解释它,答案就在错误信息中.

您正在创建一个IEnumerablevia LINQ to Entities(实体框架LINQ提供程序),如下所示:

IEnumerable<TeamAction> incomplete = dbIncAct.IncompleteActivity
  .Where(a => a.activityID == id)
  .Select(s => new TeamAction(s.teamID, s.name, id, s.type));
Run Code Online (Sandbox Code Playgroud)

请注意,您的Select调用包含一个lambda表达式,该表达式调用带有TeamAction4个参数的构造函数.一旦你要求第一个元素IEnumerable,LINQ就会尝试执行你的查询.此时,它会解析您的lambda表达式并尝试将其转换为可以运行的实体框架查询.但是,正如异常消息所说:

Only parameterless constructors and initializers are supported 
Run Code Online (Sandbox Code Playgroud)

您不能在LINQ查询中包含参数化构造函数,因为LINQ to Entities不知道如何执行它.要解决此问题,您有几个选择.

选项一:IQueryable - > IEnumerable

最简单的方法是确保EF LINQ提供程序永远不会看到有问题的lambda,因为它会在它到达之前强制IQueryable进入IEnumerable.dbIncAct.ImcompleteActivity可能是a DbSet<>,并DbSet<>.Where返回IQueryable仍依赖于LINQ 2实体的内容.要打破这种依赖性,你可以这样做:

IEnumerable<TeamAction> incomplete = dbIncAct.IncompleteActivity
  .Where(a => a.activityID == id)
  .AsEnumerable()
  .Select(s => new TeamAction(s.teamID, s.name, id, s.type));
Run Code Online (Sandbox Code Playgroud)

这将强制您的EF查询在部件中运行Where并返回可枚举的IncompleteActivity实体集合.那个东西(一些内部定义List的对象)然后用来调用Select,完全不同于EF.

这里的缺点是你迫使EF查询(可能会命中数据库)立即发生.如果您不想这样,您唯一的选择是使用其他两个选项中的一个来消除参数化构造函数.

选项二:对象初始化器

根据构造函数的作用,您可能也可能无法轻松修复它.如果您的构造函数只是在新创建的对象上设置属性,那么您很幸运.C#引入了新的对象初始化器语法,以便与LINQ和lambdas一起使用,正是出于这个原因:

IEnumerable<TeamAction> incomplete = dbIncAct.IncompleteActivity
  .Where(a => a.activityID == id)
  .Select(s => new TeamAction 
  { 
    TeamId = s.teamID, 
    Name = s.name,
    Id = id, 
    Type = s.type
  });
Run Code Online (Sandbox Code Playgroud)

方案三:重构

如果你的构造函数做了任何实际的工作,那么你需要做一些重构.尝试尽可能多地将逻辑移动到默认TeamAction()构造函数中.您也可以将一些逻辑放入属性设置器中,尽管您应该尽可能地尽量减少这些逻辑.

如果你的对象确实需要一些复杂的初始化,那么典型的模式就是在生命周期的早期调用初始化方法,例如:

var x = new X { ... };  
x.InitializeMe();
Run Code Online (Sandbox Code Playgroud)

例如,您可以在@for循环内执行此操作,也可以在创建查询后立即执行单独的步骤.