1

想要在 cshtml 中使用公共类的对象,但出现运行时错误:LINQ to Entities 中仅支持无参数构造函数和初始化程序。以下陈述有什么问题?谢谢你的帮助!

@foreach (var obj in ViewData["IncompleteList"] as IEnumerable<Games.TeamAction>)

控制器填充 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;

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

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; }
}
4

2 回答 2

5

一旦您弄清楚如何解释它,答案就在错误消息中。

您正在IEnumerable通过 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));

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

Only parameterless constructors and initializers are supported 

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

选项一:IQueryable -> IEnumerable

解决此问题的最简单方法是确保 EF LINQ 提供程序永远不会看到有问题的 lambda,方法是在它到达之前强制您IQueryable进入。可能是, 并返回仍然依赖于 LINQ 2 实体的 。要打破这种依赖关系,您可以执行以下操作:IEnumerabledbIncAct.ImcompleteActivityDbSet<>DbSet<>.WhereIQueryable

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

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

这里的缺点是您正在强制 EF 查询(可能会访问数据库)立即发生。如果您不希望这样,您唯一的选择是使用其他两个选项之一来消除参数化构造函数。

选项二:对象初始化器

根据该构造函数所做的事情,您可能无法轻松修复它。如果您的构造函数只是在那里为您新创建的对象设置属性,那么您很幸运。正是由于这个原因,C# 引入了新的对象初始化器语法以与 LINQ 和 lambda 一起使用:

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
  });

选项三:重构

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

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

var x = new X { ... };  
x.InitializeMe();

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

于 2012-11-12T16:27:47.257 回答
0

改为对象初始化:

IEnumerable<TeamAction> incomplete = dbIncAct.IncompleteActivity.Where(a => a.activityID == id)
                            .Select(s => new TeamAction { teamID = s.teamID, teamName = s.name, activityID = s.id, actionType = s.type });
于 2012-11-12T16:17:43.467 回答