我的控制器中有以下代码:
public List<DockDoorViewModel> GetDoorViewModel()
{
List<DockDoorViewModel> doors = new List<DockDoorViewModel>();
for (int i = 1; i < 11; i++)
{
// This is where the Stack Trace is pointing to.
DockDoorViewModel door = db.vwDockDoorDatas
.Where(x => x.DockNo == i)
.Select(x => x.ToDockDoorViewModel())
.FirstOrDefault();
if (door == null)
{
door = new DockDoorViewModel(i);
}
else
{
door.Items = db.vwDockDoorDatas
.Where(x => x.DockNo == i)
.Select(x => x.ToDockDoorItem())
.ToList();
}
doors.Add(door);
}
return doors;
}
当我尝试运行Web App时,我收到此异常:
异常详细信息:System.NotSupportedException:LINQ to Entities无法识别方法'DockDoorMonitor.Models.DockDoorViewModel ToDockDoorViewModel(DockDoorMonitor.Models.vwDockDoorData)'方法,并且此方法无法转换为商店表达式。
这是扩展方法:
public static class vwDockDoorDataExtensions
{
public static DockDoorViewModel ToDockDoorViewModel(this vwDockDoorData x)
{
DockDoorViewModel vm = null;
if (x != null)
{
vm = new DockDoorViewModel()
{
ID = x.ID,
DockNo = x.DockNo,
loadType = x.loadType,
LoadDescription = x.LoadDescription,
Name = x.Name,
LocationCode = x.LocationCode,
SACode = x.SACode
};
}
return vm;
}
public static DockDoorItem ToDockDoorItem(this vwDockDoorData x)
{
DockDoorItem vm = null;
if (x != null)
{
vm = new DockDoorItem()
{
ID = x.ItemNo,
Description = x.Description,
Quantity = x.Quantity,
UnitOfMeasure = x.UnitOfMeasure
};
}
return vm;
}
}
之前我做过这种事情,所以我没看到我做错了什么?这是我第一次使用MVC5和EF6应用程序。
答案 0 :(得分:5)
错误消息告诉您确实需要知道的所有内容 - EF无法将您的扩展方法转换为SQL,因此会抛出异常。您需要将查询从LINQ转换为实体到LINQ转换为对象,这可以通过简单调用AsEnumerable()
来完成,例如
DockDoorViewModel door = db.vwDockDoorDatas.Where(x => x.DockNo == i)
.AsEnumerable()
.Select(x => x.ToDockDoorViewModel())
.FirstOrDefault();
实际上,这样做是创建一个混合查询,其中AsEnumerable
之前的所有内容都被翻译并作为SQL执行,其余部分在客户端和内存中执行。
根据你的表现问题,再次查看你的查询你不必要地浏览了很多记录,你只是在第一个记录之后,所以为什么不把它拉过来呢。
vwDockDoorData entity = db.vwDockDoorDatas.Where(x => x.DockNo == i)
.FirstOrDefault();
DockDoorViewModel door = entity != null ? entity.ToDockDoorViewModel() : null;
对此进行进一步改进,只需在之前过滤记录,然后迭代它们(给你一个开始/结束范围),例如。
var doorDatas = db.vwDockDoorDatas.Where(x => x.DockNo >= 1 && x.DockNo <= 11)
.ToList();
for (int i = 0; i < doorDatas.Count; i++)
{
// This is where the Stack Trace is pointing to.
DockDoorViewModel door = data.ToDockDoorViewModel();
if (door == null)
{
door = new DockDoorViewModel(i+1);
}
else
{
door.Items = data.ToDockDoorItem();
}
doors.Add(door);
}
以上只需要一次到DB。
答案 1 :(得分:2)
在使用to方法之前,您必须从SQL Server加载数据。您可以使用以下命令执行此操作(例如):
door.Items = db.vwDockDoorDatas
.Where(x => x.DockNo == i)
.ToList() //Possibly use AsEnumerable() here instead as James says
.Select(x => x.ToDockDoorItem())
.ToList();