【问题标题】:Map ICollection<Model> to List<ViewModel> using AutoMapper使用 AutoMapper 将 ICollection<Model> 映射到 List<ViewModel>
【发布时间】:2015-04-24 19:38:21
【问题描述】:

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

LINQ to Entities 无法识别该方法 'System.Collections.Generic.List1[Web.ViewModels.FirmMatterViewModel] Map[ICollection1,List1](System.Collections.Generic.ICollection1[Web.Models.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)
    };

我已经为 FirmMatter 创建了地图

Mapper.CreateMap<FirmMatter, FirmMatterViewModel>();

我的代码有什么问题?

【问题讨论】:

标签: c# linq automapper


【解决方案1】:

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

Includes 和AsEnumerable() 的组合效率非常低,因为 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; }

【讨论】:

    【解决方案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)
    });
    

    【讨论】:

    • 谢谢,我试过你的代码,但它会生成一个新错误A query body must end with a select clause or a group clause 我认为它应该以 select 子句结尾
    • 是的,我忘记写了。只需在查询末尾添加select cm。我也修正了我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多