使用AutoMapper将ICollection <model>映射到List <viewmodel>

时间:2015-04-24 10:52:39

标签: c# linq automapper

我试图在我的代码中使用AutoMapper。映射集合时,我收到了此错误

  

LINQ to Entities无法识别该方法   &#39; {System.Collections.Generic.List {1}} 1,列表1[Web.ViewModels.FirmMatterViewModel] Map[ICollection 1 [Web.Models.FirmMatter])&#39;   方法,并且此方法无法转换为商店表达式。

这是我如何进行映射的代码:

1](System.Collections.Generic.ICollection

我为FirmMatter

创建了地图
var clientMatters = 
    from cm in db.ClientMatters
        .Include(t => t.Billing)
        .Include(t => t.Billing.Office)
        .Include(t => t.Billing.Client)
        .Include(t => t.FirmMatters)
    select new ClientMatterIndexListViewModel
    {
        ClientMatterID = cm.ClientMatterID,
        BillingID = cm.BillingID,
        OfficeName = cm.Billing.Office.Name,
        ClientName = cm.Billing.Client.Name,
        ClientMatterNo = cm.ClientMatterNo,
        Description = cm.Description,
        FirmMatters = Mapper.Map<ICollection<FirmMatter>, List<FirmMatterViewModel>>(cm.FirmMatters)
    };

我的代码出了什么问题?

2 个答案:

答案 0 :(得分:3)

我知道你接受了答案,但我要么不使用AutoMapper,要么一直使用AutoMapper。

IncludeAsEnumerable()的组合非常低效,因为SQL语句将SELECT所有表的所有列并将此膨胀的结果集拉入内存。最后,您只需要非常有限的属性。为什么不寻找一种只选择所需数据的方法呢?

没有AutoMapper

没有AsEnumerable()和AM以及内联投影的查询效率更高:

var clientMatters = 
    from cm in db.ClientMatters
    select new ClientMatterIndexListViewModel
    {
        ClientMatterID = cm.ClientMatterID,
        BillingID = cm.BillingID,
        OfficeName = cm.Billing.Office.Name,
        ClientName = cm.Billing.Client.Name,
        ClientMatterNo = cm.ClientMatterNo,
        Description = cm.Description,
        FirmMatters = cm.FirmMatters.Select(fm => new FirmMatterViewModel { ... } }
    };

您不需要此处的“包含”,因为查询不会返回可包含集合和引用的ClientMatter个对象。在select中使用这些导航属性足以让EF生成所有必需的连接。

使用AutoMapper

如果您还定义了ClientMatterClientMatterIndexListViewModel之间的映射,则可以使用AutoMapper的Project.To方法获得与上一个查询相同的效果:

using AutoMapper.QueryableExtensions;
...

var clientMatters = db.ClientMatters
                      .Project().To<ClientMatterIndexListViewModel>();

为了实现这一点,ClientMatterIndexListViewModel应包含如下属性:

public IEnumerable<FirmMatterViewModel> FirmMatters { get; set; }

答案 1 :(得分:2)

LINQ to Entities尝试将Map方法转换为SQL,这显然是可撤消的。要避免该错误,您应该在调用map之前将查询转换为可枚举:

var query = 
    from cm in db.ClientMatters
        .Include(t => t.Billing)
        .Include(t => t.Billing.Office)
        .Include(t => t.Billing.Client)
        .Include(t => t.FirmMatters)
    select cm;

var clientMatters = query.AsEnumerable().Select(cm => new ClientMatterIndexListViewModel
{
    ClientMatterID = cm.ClientMatterID,
    BillingID = cm.BillingID,
    OfficeName = cm.Billing.Office.Name,
    ClientName = cm.Billing.Client.Name,
    ClientMatterNo = cm.ClientMatterNo,
    Description = cm.Description,
    FirmMatters = Mapper.Map<ICollection<FirmMatter>, List<FirmMatterViewModel>>(cm.FirmMatters)
});