实体框架和自动映射中的数据投影

时间:2011-03-22 13:04:12

标签: c# entity-framework linq-to-entities automapper

我想使用AutoMapper构建一个ViewModel(展平 - 数据投影),以便在ASP.net MVC应用程序中使用。

var tmp = from x in db.Mailings select Mapper.Map<Mailing, MailingViewModel>(x);
return View(tmp.ToList());

当然,当我尝试上面的示例时,我得到EF错误“LINQ to Entities无法识别方法...方法,并且此方法无法转换为存储表达式。”

我知道可以在Automapper发挥其魔力之前移动.ToList(),但之后我从Db中获取所有字段(我只需要20个字段中的3个)

是否可以以干净的方式使用它。 Clean =并非所有字段都是从DB中提取的,而只是ViewModel所需的字段。在Automapper中有可能吗?或者也许是其他图书馆? (不做手动;))

7 个答案:

答案 0 :(得分:9)

是的,这很有可能。见http://www.devtrends.co.uk/blog/stop-using-automapper-in-your-data-access-code

编辑:我最近发现AutoMapper中已存在此基础。为AutoMapper.QueryableExtensions添加一个using语句,并为您提供名为Project&lt;&gt;()的IQueryable扩展

答案 1 :(得分:4)

您只需致电:

var tmp = from x in db.Mailings 
          select new MailingViewModel
            {
               FirstName = x.FirstName,
               LastName = x.LastName,
               Address = x.Address
            };

如果直接在控制器中访问EF,则不需要使用AutoMapper进行简单投影。

您无法在linq-to-entities查询中涉及AutoMapper - 没办法。您必须返回实体(或其他投影对象)并通过AutoMapper进行映射,或者在没有AutoMapper的情况下使用普通投影。

答案 2 :(得分:2)

这是由linq与IQueryableProviders交互的方式引起的(我认为这是界面)。

所以发生的事情是Linq被编译到一个表达式树,底层的linq提供程序读取并尝试转换为sql。 linq提供程序不知道如何将Mapper.Map<>转换为SQL,因此错误。

关于linq提供商如何工作的好视频,请查看:http://channel9.msdn.com/Shows/Going+Deep/Erik-Meijer-and-Bart-De-Smet-LINQ-to-Anything

答案 3 :(得分:2)

您应该可以使用AutoMapper的DynamicMap执行此操作。如果您真的想使用AutoMapper,我相信类似下面的窗台会解决您的问题,尽管在这种特殊情况下我同意Ladislav Mrnka。

var tmp = from x in db.Mailings 
          select new
          {
              FirstName = x.FirstName,
              LastName = x.LastName,
              Address = x.Address
          };

return View(tmp.ToList().Select(item => Mapper.Map<MailingViewModel>(item)));

不幸的是,如果要限制从数据库返回的列,则需要指定所需的列,这在这种情况下无法实现AutoMapper的目的。这将是一个非常巧妙的AutoMapper扩展,获取目标类型并根据类型的属性动态创建一个选择表达式。

答案 4 :(得分:1)

这可以使用LINQ Projector库完成。它基于http://www.devtrends.co.uk/blog/stop-using-automapper-in-your-data-access-code并添加了一些映射约定。

答案 5 :(得分:1)

因为Automapper不能直接用于数据库(在解决之前需要转换为内存中的对象),所以我编写了自己的简单类来复制相同的属性:

初始代码:

  model.Sales = _dbcontext.Sales.Where(o => o.PartnerId == PartnerId && (o.SaleDate > model.BeginDate || model.BeginDate == null) && (o.SaleDate <= model.EndDate || model.EndDate == null)).Select(o => new SaleViewModel
        {
            NumberIn1S = o.NumberIn1S,
            Total = o.Total,
            SaleDate = o.SaleDate,
            Comments = o.Comments,
            Driver = o.Driver,
            GuidIn1S = o.GuidIn1S
        }).OrderByDescending(o => o.SaleDate).ToList(); </p>

MyMapper:

model.Sales = _dbcontext.Sales.Where(o => o.PartnerId == PartnerId && (o.SaleDate > model.BeginDate || model.BeginDate == null) && (o.SaleDate <= model.EndDate || model.EndDate == null)).OrderByDescending(o => o.SaleDate).ToArray().Select(p => <b>MyMapper<SaleViewModel>.CopyObjProperties(p, "NumberIn1S,Total,SaleDate,Comments,Driver,GuidIn1S")</b>).ToList(); </p>

答案 6 :(得分:1)

我认为 automapper 仍然可以直接使用 DB

query.ProjectTo<YourObjectDto>(_mapper.ConfigurationProvider).ToList

在我的 MVC 5 应用程序中,我注入 IMapper 并获得 _mapper.ConfigurationProvider