在.NET中将IQueryable映射到OData的域模型

Tyl*_*own 5 .net c# iqueryable automapper odata

我最近在ASP .NET Core Web API中实现了OData。只要我直接返回数据库模型,就可以找到成功。但是,当我尝试返回域模型时,便遇到了麻烦。

潜在的问题涉及在保持IQueryable返回类型的同时将数据类映射到域类。虽然我发现使用AutoMapper的MapTo扩展方法部分成功,但是我发现使用$ extend方法扩展也是域对象的实体集时不成功。

我创建了一个示例项目来说明此问题。您可以查看或下载完整的项目在GitHub上这里。请参阅下面的说明。

给定以下两个数据库类:

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; }    
}
Run Code Online (Sandbox Code Playgroud)

还有以下领域模型...

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; }
}
Run Code Online (Sandbox Code Playgroud)

和产品控制器

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

以下所有OData查询均通过:

但是,以下查询未通过:

永远不会返回HTTP响应。我收到的唯一失败消息来自控制台:

System.InvalidOperationException: Sequence contains no matching element at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source, Func`2 predicate)
Run Code Online (Sandbox Code Playgroud)

最后,这里是对映射配置文件的引用:

    public static class MappingProfile
{
    public static void RegisterMappings() {
        Mapper.Initialize(cfg =>
        {
           cfg.CreateMap<Order, OrderEntity>();
           cfg.CreateMap<Product, ProductEntity>();
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

我可以通过在控制器中简单地返回一个List而不是IEnumerable来解决此问题,但这当然会触发对数据库的大查询,而这将占用大量性能。

如上所述,你可以找到一个链接到Github上完整的项目在这里。让我知道是否找到答案!

Par*_*and 2

我通过一些小的修改就可以让它工作。

更新域模型:

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; }
}
Run Code Online (Sandbox Code Playgroud)

在路线构建器上手动启用扩展:

// 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));
        });
}
Run Code Online (Sandbox Code Playgroud)

使用以下查询: