【问题标题】:How to apply ODataQueryOptions for DTO to underlying EntitySet?如何将 DTO 的 ODataQueryOptions 应用于基础 EntitySet?
【发布时间】:2016-03-20 23:54:51
【问题描述】:

有 2 个类,Foo 和 Bar。 Foo 对象中嵌套了一个 Bar 对象。

public class Foo {
    public Guid FooId { get; set; }
    public string FooName { get; set; }
    [ForeignKey("Bar")]
    public Guid BarId { get; set; }

    public virtual Bar Bar { get; set; }
}

public class Bar {
    public Guid BarId { get; set; }
    public string BarName { get; set; }
}

public class FooBarContext : DbContext {
    public DbSet<Foo> Foos { get; set; }
    public DbSet<Bar> Bars { get; set; }
}

public class FooDTO {
    public Guid FooId { get; set; }
    public string FooName { get; set; }
    public Guid BarId { get; set; }
    public string BarName { get; set; }
}

我的问题是:我能否以某种方式将 FooDTO 的 OData 查询转换为 Foo 的 OData 查询,以便将其应用于 Foos DbSet?

例如,我想通过 BarName 进行查询,它最终来自嵌套的 Bar 对象。

GET /Foos?$filter=BarName eq 'Bar2'

这是处理查询的控制器和操作

public class FoosController {
    public async Task<IHttpActionResult> GetFoos(ODataQueryOptions<FooDTO> queryOptions) {
        // translate filter FooDTO.BarName to filter Foo.Bar.Name
        // ODataQueryOptions<Foo> fooQueryOptions = ....
        using (var context = new FooBarContext()) {
            return fooQueryOptions.ApplyTo(context.Foos);
        }
    }
}

谢谢。

【问题讨论】:

  • 你的问题解决了吗?
  • @Tymek 抱歉回复晚了。我最终实施了自己的解决方案,放弃了 OData。但是,如果您想使用 OData,据我所知,仅有的 2 个选项是 AutoMapper,以及自己解析和构建查询。解析OData查询请参考这篇文章ben-morris.com/…

标签: c# entity-framework asp.net-web-api odata


【解决方案1】:

首先将 OData 包安装到您的 Web API 项目中

Install-Package Microsoft.AspNet.OData -Version 7.1.0

通过添加以下using 语句在WebApiConfig.cs 中配置OData 端点

using System.Web.OData.Builder;
using System.Web.OData.Extensions;

然后在Register 方法中添加代码

public static void Register(HttpConfiguration config)
{
    config.MapHttpAttributeRoutes();

    // New code start
    ODataModelBuilder builder = new ODataConventionModelBuilder();
    builder.EntitySet<Foo>("Foos");
    builder.EntitySet<Bar>("Bars");
    config.MapODataServiceRoute(
        routeName: "ODataRoute",
        routePrefix: null,
        model: builder.GetEdmModel());

    config.Count().Filter().OrderBy().Expand().Select().MaxTop(null);

    config.EnableDependencyInjection();
    // New code end

    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
}

为映射更新:在您的控制器中

[EnableQuery()] // Enables clients to modify the query, by using query options such as $filter, $sort, and $page
public async Task<IHttpActionResult> GetFoos(ODataQueryOptions<FooDTO> queryOptions)
{
    using (var context = new FooBarContext())
    {
        return queryOptions.ApplyTo(context.Foos.AsQueryable().Select(f => new FooDTO
        {
            BarId = f.BarId,
            BarName = f.Bar.BarName,
            FooId = f.FooId,
            FooName = f.FooName
        }));
    }
}

更多请查看Create an OData v4 Endpoint Using ASP.NET Web API

还有Supercharging your Web APIs with OData and ASP.NET Core(对于.Net core,但它可以提供帮助)

【讨论】:

  • 嗯...这行得通,但是如果它们来自 EntityFramework 上下文,最后一个代码 sn-p 中的 Select 语句不会将所有 Foos 加载到内存中吗?并且查询将应用于所有Foos 的物化列表?这意味着如果有大量Foos,这是一个非常糟糕的主意?
  • @S'pht'Kr 在这种情况下不是,因为这种转换可以转换为 SQL 查询,但情况可能并非总是如此
猜你喜欢
  • 2016-10-11
  • 1970-01-01
  • 2021-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-30
  • 1970-01-01
相关资源
最近更新 更多