IQueryable Lambda 投影语法

发布于 2024-09-29 16:13:18 字数 2092 浏览 13 评论 0原文

我有一个 IQueryable,我想将其 Entity Framework 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 投影的适当语法是什么?谢谢。

PS Automapper 配置正确 - 我在其他地方使用它在 Person 和 PersonP 之间来回转换,即 Mapper.Map(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>成为其中之一。我可以使用这些重载之一来表示此函数/委托调用吗?

I have an IQueryable whose Entity Framework 4 objects I would like to project to their DTO equivalents. One such object 'Person' is an EF4 class, and the corresponding POCO PersonP is a class I've defined. I am using Automapper to map between them. However, when I try the following code:

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

The projection generates this error at runtime:

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.

What is the appropriate syntax to create a IQueryable<PersonP> projection using Automapper? Thank you.

P.S. Automapper is configured correctly - I use it in other places to convert back and forth between Person and PersonP, i.e. Mapper.Map<Person, PersonP>(myPersonObject) correctly returns a PersonP object.

EDIT (more code):

I'm using this for a helper function to bind EF4 Entity POCOs (PersonP) to a Telerik Grid - which will not serialize the entities themselves properly since they contain circular references (i.e. navigation properties). My code looks like this:

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...
}

the .ToGridModel method is an extension method on IQueryable and it returns a complex object which I cannot reliably parse - so this leads me to believe I have to perform the filtering after I've done the projection to POCOs.

UPDATE 2:

Trying to simplify things, I made a non-generic method like this:

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 };
}

This code also fails when creating the projection. I notice that IQueryable.Select() has multiple overloads: Expression> being one of them. Could I represent this function/delegate call using one of these overloads?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

酒废 2024-10-06 16:13:18

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

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

另请参阅后续文章< /a> 由 Paul Hiles 进行一些缓存改进。

希望这有帮助。

This has actually been solved now by the author of AutoMapper here: http://lostechies.com/jimmybogard/2011/02/09/autoprojecting-linq-queries/

He provides an implementation that takes a desired projection and the query and queries the database for only the fields needed for the projection mapping.

Also, see the follow-on article by Paul Hiles for some caching improvements.

Hope this helps.

何止钟意 2024-10-06 16:13:18

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

没有一个。 Automapper 不会执行此操作。对于这项工作来说,这是错误的工具。

人们可以创建一个类似 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);

...那么它就会起作用。

What is the appropriate syntax to create a IQueryable projection using Automapper?

There isn't one. Automapper doesn't do this. It's the wrong tool for this job.

One could create an Automapper-like tool to do a similar thing for query projections. I've considered it in the past, but always concluded that code using it would be less readable than the projection. I don't want to optimize code-writing time over code-reading time.

Your updated code doesn't work because it isn't an expression. If you do:

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

...and then:

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

...then it will work.

-黛色若梦 2024-10-06 16:13:18

如果在 Select 之前添加 .ToList() ,则可以强制映射发生在客户端(Linq to Objects)而不是服务器端(SQL)。只要确保您首先完成了过滤,这样就不会把整个表都带过来。

If you add .ToList() before the Select you can force the mapping to happen client-side (Linq to Objects) instead of server side (SQL). Just make sure you've done your filtering first so you aren't bringing the whole table over.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文