实体框架使用扩展方法抛出异常

时间:2013-11-19 15:44:05

标签: c# asp.net-mvc entity-framework

我的控制器中有以下代码:

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应用程序。

2 个答案:

答案 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();