C# 实体框架和Automapper中的数据投影

C# 实体框架和Automapper中的数据投影,c#,entity-framework,linq-to-entities,automapper,C#,Entity Framework,Linq To Entities,Automapper,我想使用AutoMapper构建一个ViewModel(展平-数据投影),用于ASP.NETMVC应用程序 var tmp = from x in db.Mailings select Mapper.Map<Mailing, MailingViewModel>(x); return View(tmp.ToList()); var tmp=db.Mailings中的x选择Mapper.Map(x); 返回视图(tmp.ToList()); 当然,当我尝试上面的示例时,会出现EF错误

我想使用AutoMapper构建一个ViewModel(展平-数据投影),用于ASP.NETMVC应用程序

var tmp = from x in db.Mailings select Mapper.Map<Mailing, MailingViewModel>(x);
return View(tmp.ToList());
var tmp=db.Mailings中的x选择Mapper.Map(x);
返回视图(tmp.ToList());
当然,当我尝试上面的示例时,会出现EF错误“LINQ to Entities无法识别方法…方法,并且此方法无法转换为存储表达式。”

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

有没有可能以干净的方式使用它。Clean=并非所有字段都从数据库中获取,而是仅从ViewModel所需的字段中获取。在Automapper有可能吗?或者是另一个图书馆?(无需手动操作;)

您只需调用:

var tmp = from x in db.Mailings 
          select new MailingViewModel
            {
               FirstName = x.FirstName,
               LastName = x.LastName,
               Address = x.Address
            };
若您直接在控制器中访问EF,则不需要AutoMapper进行简单的投影


您不能在linq到实体查询中使用AutoMapper-不可能。您必须返回实体(或另一个投影对象)并通过AutoMapper对其进行映射,或者使用不带AutoMapper的普通投影。

这是由linq与IQueryableProviders交互的方式造成的(我认为这是接口)

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


有关linq提供者如何工作的好视频,请查看:

您应该能够使用AutoMapper的。如果你真的想使用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)));
var tmp=以db.Mailings为单位从x开始
选择新的
{
FirstName=x.FirstName,
LastName=x.LastName,
地址=x.地址
};
返回视图(tmp.ToList().Select(item=>Mapper.Map(item));

不幸的是,如果要限制从数据库返回的列,则需要指定所需的列,这在本场景中确实不符合AutoMapper的目的。不过,这将是一个非常简洁的AutoMapper扩展,它采用目标类型并根据类型的属性动态创建一个select表达式。

是的,这是非常可能的。看这里


编辑:我最近发现AutoMapper中已经存在这方面的基础。为AutoMapper.QueryableExtensions添加一个using语句,您将获得一个名为Project()的IQueryable扩展。

这可以通过使用库来完成。它基于并添加了一些映射约定。

由于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>
model.Sales=\u dbcontext.Sales.Where(o=>o.PartnerId==PartnerId&&(o.SaleDate>model.BeginDate | | model.BeginDate==null)&&(o.SaleDate新SaleViewModel)
{
NumberIn1S=o.NumberIn1S,
总计=o.总计,
SaleDate=o.SaleDate,
注释=o.注释,
驱动器=o.驱动器,
GuidIn1S=o.GuidIn1S
}).OrderByDescending(o=>o.SaleDate).ToList()

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>
model.Sales=\u dbcontext.Sales.Where(o=>o.PartnerId==PartnerId&&(o.SaleDate>model.BeginDate | | model.BeginDate==null)&(o.SaleDate o.SaleDate).ToArray()。选择(p=>MyMapper.CopyObjProperties(p,“NumberIn1S,Total,SaleDate,Comments,Driver,GuidIn1S”)。ToList()


我认为automapper仍然可以直接与DB合作

query.ProjectTo(\u mapper.ConfigurationProvider).ToList


在我的MVC 5应用程序中,我注入
IMapper
并获取
\u mapper.ConfigurationProvider

是的,但我很懒;)不严重;我很好奇它是否可以自动完成…(这个示例只有几个字段,但在+20个字段的情况下,字段来自多个联接等。)这在技术上是不正确的,你可以这样做。请看@brentmckendrick:哪一部分在技术上是不正确的?你正确地指的是一个更好的解决方案,但该解决方案并没有说我的答案是错误的。它再次声称,用AutoMapper实现这一点是不可能的。很抱歉,我没有冒犯你的意思。我指的是e句“在linq到实体查询中不能涉及AutoMapper-不可能”这并不完全正确,因为我们可以创建一个扩展方法,自动从automapper的成员映射创建一个表达式,这样我们就不需要自己编写表达式。还有更多。automapper实际上已经有了这些扩展方法一段时间了…(昨天刚刚了解到)-->这相当“危险”在投影中使用AutoMapper,因为如果在地图中有展平操作(
target.Prop1=source.Ref1.Prop1
),可能会创建一个N+1场景。您建议的扩展确实是我正在寻找的解决方案。太糟糕了,我的表达式树知识非常有限:)实际上,我已经创建了您提到的扩展方法,它可以工作。。。直到某一点。如果您试图填充一个具有ICollection/List/array等属性的实体(并且您还希望具体化这些实体的投影),那么它会中断,因为SQL提供程序不允许您在查询中调用ToList()。我在这里写过关于这个问题的文章,如果他们只是解决了这个问题,那么我们都可以通过利用automapperNice解决方案来编写单线投影!通常最好让你的答案更具解释性——特别是在提供的链接将停止工作的情况下。昨天我也看到了这篇博文。正是我要找的东西!很好,据我所知,它没有列举。如果是的话