一旦您弄清楚如何解释它,答案就在错误消息中。
您正在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 表达式,该表达式调用带有TeamAction
4 个参数的构造函数。只要您请求 中的第一个元素IEnumerable
,LINQ 就会尝试执行您的查询。此时,它会解析您的 lambda 表达式并尝试将其转换为可以运行的实体框架查询。但是,正如异常消息所说:
Only parameterless constructors and initializers are supported
您不能在 LINQ 查询中包含参数化构造函数,因为 LINQ to Entities 不知道如何执行它。要解决此问题,您有几个选择。
选项一:IQueryable -> IEnumerable
解决此问题的最简单方法是确保 EF LINQ 提供程序永远不会看到有问题的 lambda,方法是在它到达之前强制您IQueryable
进入。可能是, 并返回仍然依赖于 LINQ 2 实体的 。要打破这种依赖关系,您可以执行以下操作:IEnumerable
dbIncAct.ImcompleteActivity
DbSet<>
DbSet<>.Where
IQueryable
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
循环内执行此操作,也可以在创建查询后立即作为单独的步骤执行此操作。