2011-03-22 90 views
5

我想使用AutoMapper构建一个ViewModel(展平 - 数据投影),以便在ASP.net MVC应用程序中使用。实体框架和自动映射器中的数据投影

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

当然,当我尝试上面的例子,我得到的EF错误“LINQ到实体无法识别方法...方法,该方法不能被翻译成店的表达。”

我知道这是可以移动Automapper做它的魔力前.ToList(),但后来我取从数据库中的所有字段(而我只需要3个20场)

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

+0

这是非常 “危险” 的使用AutoMapper的预测,因为如果你在地图上有一个扁平化操作('target.Prop1 = source.Ref1.Prop1')你MIG ht创建一个N + 1场景。 – 2011-03-22 13:50:10

回答

9

是的,这是非常可能的。看到这里http://www.devtrends.co.uk/blog/stop-using-automapper-in-your-data-access-code

编辑:我最近发现,它的基础已经存在于AutoMapper中。为AutoMapper.QueryableExtensions添加using语句,并提供名为Project <>()

+0

好的解决方案!通常最好让你的答案更具说明性 - 尤其是对于提供链接停止工作的情况。 – 2012-07-17 09:10:53

+0

昨天我也看到了这篇博文。就是我一直在寻找的东西! – 2012-07-20 06:53:25

+0

非常好,据我所知它不枚举。如果是这样,那真的是我需要的。 – 2013-02-08 12:24:38

4

您只需拨打:

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

如果直接在控制器访问EF不需要AutoMapper简单的投影。

你不能将AutoMapper包含在linq-to-entities查询中 - 没办法。您必须返回实体(或另一个投影对象)并将其映射到AutoMapper或使用普通投影,而不使用AutoMapper。

+0

是的,但我很懒惰;)没有认真;我很好奇它是否可以自动完成......(这个例子只有几个字段,但有些情况下+20字段的字段来自多个连接等) – 2011-03-22 13:45:05

+0

我更新了我的答案。 – 2011-03-22 13:50:10

+0

这在技术上不正确,你可以这样做。见http://www.devtrends.co.uk/blog/stop-using-automapper-in-your-data-access-code – brentmckendrick 2012-07-17 08:00:04

2

你应该能够做到这一点使用AutoMapper的DynamicMap。我相信像下面的sill可以解决你的问题,如果你真的想使用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扩展,但要采用目标类型并根据类型的属性动态创建选择表达式。

+0

你推荐的扩展确实是我正在寻找的解决方案。太糟糕了,我的表达树的知识是相当有限的:) – 2011-03-22 18:26:50

+0

我实际上已经创建了你引用的扩展方法,它的工作原理...直到一个点。如果您试图填充具有ICollection/List/array等属性的实体(并且您还想实现这些实体的投影),那么它会中断,因为SQL提供程序不会让您调用ToList( )在一个查询中。我已经写过关于这个问题http://refactorthis.wordpress.com/2012/07/20/entity-framework-tolist-in-nested-type-linq-to-entities-does-not-recognize-the-方法/如果他们只是解决这个问题,那么我们可以通过利用automapper来编写一行预测。 – brentmckendrick 2012-12-13 09:12:47

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>