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

Ref*_*din 1 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;
}
Run Code Online (Sandbox Code Playgroud)

当我尝试运行Web应用程序时,我收到此异常:

异常详细信息: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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我以前做过这种事情所以我没看到我做错了什么?这是我第一次使用MVC5和EF6应用程序.

Jam*_*mes 5

错误消息告诉您确实需要知道的所有内容 - EF无法将您的扩展方法转换为SQL,因此会抛出异常.您需要查询的LINQ转换为实体到LINQ到对象,这可以用一个简单的调用来完成AsEnumerable()

DockDoorViewModel door = db.vwDockDoorDatas.Where(x => x.DockNo == i)
                                           .AsEnumerable()
                                           .Select(x => x.ToDockDoorViewModel())
                                           .FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)

实际上,它的作用是创建一个混合查询,其中所有内容都AsEnumerable被转换并作为SQL执行,其余部分在客户端和内存中执行.


根据你的性能问题,再次查看你的查询你不必要地浏览了很多记录,你只是在第一个记录之后,所以为什么不把它拉过来ie

vwDockDoorData entity = db.vwDockDoorDatas.Where(x => x.DockNo == i)
                                          .FirstOrDefault();
DockDoorViewModel door = entity != null ? entity.ToDockDoorViewModel() : null;
Run Code Online (Sandbox Code Playgroud)

对此的进一步改进是迭代记录之前简单地过滤记录(给你一个开始/结束范围),例如

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);
}
Run Code Online (Sandbox Code Playgroud)

以上只需要一次DB.