[英]Mapping an IQueryable to domain model for OData in .NET
I recently implemented OData in my ASP .NET Core web API. 我最近在我的ASP .NET Core web API中实现了OData。 I have found success as long as I am returning the database models directly.
只要我直接返回数据库模型,我就找到了成功。 I run into trouble, however, as soon as I attempt to return domain models instead.
但是,一旦我尝试返回域模型,我就会遇到麻烦。
The underlying issue involves mapping a data class to a domain class while maintaining the IQueryable return type. 底层问题涉及将数据类映射到域类,同时保持IQueryable返回类型。 While I have found partial success using AutoMapper's MapTo extension method, I find that I am unsuccessful when using the $extend method to expand a collection of entities that are also domain objects.
虽然我发现使用AutoMapper的MapTo扩展方法取得了部分成功,但我发现在使用$ extend方法扩展同样是域对象的实体集合时,我不成功。
I have created a sample project to illustrate this issue. 我已经创建了一个示例项目来说明这个问题。 You may view or download the full project on github here .
您可以在这里查看或下载github上的完整项目。 See the description below.
请参阅以下说明。
Given the following two database classes: 给出以下两个数据库类:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<Order> Orders { get; set; }
public Product() {
Orders = new Collection<Order>();
}
}
public class Order
{
public int Id { get; set; }
public Double Price { get; set; }
public DateTime OrderDate { get; set; }
[Required]
public int ProductId { get; set; }
public Product Product { get; set; }
}
And the following domain models... 以下域名模型......
public class ProductEntity
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<OrderEntity> Orders { get; set; }
}
public class OrderEntity
{
public int Id { get; set; }
public Double Price { get; set; }
public DateTime OrderDate { get; set; }
[Required]
public int ProductId { get; set; }
public Product Product { get; set; }
}
And the Products Controller 和产品控制器
public class ProductsController
{
private readonly SalesContext context;
public ProductsController(SalesContext context) {
this.context = context;
}
[EnableQuery]
public IQueryable<ProductEntity> Get() {
return context.Products
.ProjectTo<ProductEntity>()
.AsQueryable();
}
}
All the following OData queries Pass: 以下所有OData查询通过:
The following query, however, does not pass: 但是,以下查询未通过:
An HTTP response is never returned. 永远不会返回HTTP响应。 The only failure message I get comes from the console:
我得到的唯一失败消息来自控制台:
System.InvalidOperationException: Sequence contains no matching element at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source, Func`2 predicate)
Finally, here is a reference to the mapping profile: 最后,这里是对映射配置文件的引用:
public static class MappingProfile
{
public static void RegisterMappings() {
Mapper.Initialize(cfg =>
{
cfg.CreateMap<Order, OrderEntity>();
cfg.CreateMap<Product, ProductEntity>();
});
}
}
I can solve the issue by simply returning a List instead of an IEnumerable in the controller, but this of course would trigger a large query against the database that would be performance intensive. 我可以通过简单地在控制器中返回List而不是IEnumerable来解决问题,但这当然会触发针对性能密集型数据库的大型查询。
As stated above, you can find a link to the full project on Github here . 如上所述,您可以在此处找到Github上完整项目的链接。 Let me know if you find any answers!
如果您找到任何答案,请告诉我!
I was able to get this working with a few small revisions. 我能够通过一些小修改来实现这一点。
Updating the domain models: 更新域模型:
public class ProductEntity
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<Order> Orders { get; set; }
}
public class OrderEntity
{
public int Id { get; set; }
public double Price { get; set; }
public DateTime OrderDate { get; set; }
[Required]
public int ProductId { get; set; }
public Product Product { get; set; }
}
Manually enabling expansion on the route builder: 在路由构建器上手动启用扩展:
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, SalesModelBuilder modelBuilder)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc(routeBuilder =>
{
routeBuilder.Expand().Select();
routeBuilder.MapODataServiceRoute("ODataRoutes", "odata",
modelBuilder.GetEdmModel(app.ApplicationServices));
});
}
Using the following Queries: 使用以下查询:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.