使用 AutoMapper 将 ICollection<Model> 映射到 List<ViewModel>

Map ICollection<Model> to List<ViewModel> using AutoMapper

我正在尝试在我的代码中使用 AutoMapper。映射集合时,出现此错误

LINQ to Entities does not recognize the method 'System.Collections.Generic.List1[Web.ViewModels.FirmMatterViewModel] Map[ICollection1,List1](System.Collections.Generic.ICollection1[Web.Models.FirmMatter])' method, and this method cannot be translated into a store expression.

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

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)
    };

我已经为 FirmMatter 创建了地图

Mapper.CreateMap<FirmMatter, FirmMatterViewModel>();

我的代码有什么问题?

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)
});

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

Includes 和 AsEnumerable() 的组合效率很低,因为 SQL 语句将 SELECT 所有表的所有列并将这个臃肿的结果集拉入内存.最后你只需要非常有限的属性。为什么不寻找一种只 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 { ... } }
    };

此处不需要包含,因为查询不会 return 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; }