IQueryable Lambda投影语法

时间:2010-10-28 07:04:59

标签: linq-to-entities lambda linq-to-objects iqueryable projection

我有一个IQueryable,其实体框架4对象我想投影到他们的DTO等价物。一个这样的对象'Person'是EF4类,相应的POCO PersonP是我定义的类。我正在使用Automapper在它们之间进行映射。但是,当我尝试以下代码时:

IQueryable<Person> originalModel = _repo.QueryAll();
IQueryable<PersonP> projection = originalModel.Select(e => Mapper.Map<Person, PersonP>(e));

投影在运行时生成此错误:

LINQ to Entities does not recognize the method 'TestSite.Models.PersonP Map[Person,PersonP](TestSite.DataLayer.Model.Person)' method, and this method cannot be translated into a store expression.

使用Automapper创建IQueryable<PersonP>投影的合适语法是什么?谢谢。

P.S。 Automapper配置正确 - 我在其他地方使用它在Person和PersonP之间来回转换,即Mapper.Map<Person, PersonP>(myPersonObject)正确返回PersonP个对象。

编辑(更多代码):

我正在使用它来帮助函数将EF4实体POCO(PersonP)绑定到Telerik网格 - 由于它们包含循环引用(即导航属性),因此不会正确地序列化实体本身。我的代码如下所示:

public static GridModel GetGridModel<TEntity, TPoco>(IRepository<TEntity> repo, GridState gridState) where TEntity : EntityObject
{
 var originalModel = repo.QueryAll().ToGridModel(gridState);
 var projection = originalModel.Select(e => Mapper.Map<TEntity, TPoco>(e));


 return projection.ToGridModel(gridState); // applies filters, sorts, pages, etc...
}

.ToGridModel方法是IQueryable上的扩展方法,它返回一个我无法可靠解析的复杂对象 - 所以这让我相信在完成之后我必须执行过滤向POCO投射。

更新2:

为了简化事情,我做了一个非通用的方法:

public static GridModel GetGridModel2(IRepository<Client> repo, GridState gridState)
{
 IQueryable<Client> originalModel = repo.QueryAll();
 IQueryable<ClientP> projection = originalModel.Select(c => ClientToClientP(c));

 return projection.ToGridModel(gridState);
}

private static ClientP ClientToClientP(Client c)
{
 return new ClientP { Id = c.Id, FirstName = c.FirstName };
}

创建投影时,此代码也会失败。我注意到IQueryable.Select()有多个重载:Expression&gt;成为其中之一。我可以使用其中一个重载来表示此函数/委托调用吗?

3 个答案:

答案 0 :(得分:11)

AutoMapper的作者现在已经解决了这个问题:http://lostechies.com/jimmybogard/2011/02/09/autoprojecting-linq-queries/

他提供了一个实现,它采用所需的投影和查询,并仅在数据库中查询投影映射所需的字段。

另外,请参阅Paul Hiles的follow-on article以获得一些缓存改进。

希望这有帮助。

答案 1 :(得分:5)

  

使用Automapper创建IQueryable投影的合适语法是什么?

没有一个。 Automapper doesn't do this。这是这项工作的错误工具。

可以创建一个类似Automapper的工具来为查询投影做类似的事情。我过去曾考虑过它,但总是得出结论,使用它的代码比投影的可读性差。我不想在代码读取时间内优化代码写入时间。

您更新的代码不起作用,因为它不是表达式。如果你这样做:

private static Expression<Func<Client, ClientP>> ClientP ClientToClientP()
{
    return c => new ClientP { Id = c.Id, FirstName = c.FirstName };
}

......然后:

IQueryable<Client> originalModel = repo.QueryAll();
Expression<Func<Client, ClientP>> exp = ClientToClientP();
IQueryable<ClientP> projection = originalModel.Select(exp);

...然后它会起作用。

答案 2 :(得分:2)

如果在Select之前添加.ToList(),则可以强制映射发生在客户端(Linq to Objects)而不是服务器端(SQL)。只要确保你已经完成了过滤,所以你不要把整个表格都过来。