如何将 ODataQueryOptions<T> 应用于 IQueryable<X>
Posted
技术标签:
【中文标题】如何将 ODataQueryOptions<T> 应用于 IQueryable<X>【英文标题】:How to apply ODataQueryOptions<T> to IQueryable<X> 【发布时间】:2016-10-11 04:07:49 【问题描述】:我希望将 ODataQueryOptions 应用于 DbSet。让我快速介绍一下我的应用程序。我需要创建一个从两个表 T1 和 T2 读取数据的应用程序。除了每个表之外,这两个表都具有几乎相同的架构,除了几列。我的实体类设计有点像下面:(为简洁起见,我保持架构和命名简单)
class Base
[Key]
public int ID;
public string Name;
public string Gender;
public string Comment;
[Table("T1")]
class TableOneEntity : Base
[Table("T2")]
class TableTwoEntity : Base
// extra columns from T2
public string Country;
public string City;
DbContext 类:
class ApplicationDbContext : DbContext
public DbSet<TableOneEntity> TableOneDbSet;
public DbSet<TableTwoEntity> TableTwoDbSet;
我的 OData GET API 如下所示:
public PageResult<TableTwoEntity> GetTableResult(ODataQueryOptions<TableOneEntity> options)
var result1 = options.ApplyTo(appDbCtx.TableOneDbSet) as IQueryable<TableOneEntity>;
var result2 = options.ApplyTo(appDbCtx.TableTwoDbSet) as IQueryable<TableTwoEntity>;
return new PageResult<TableTwoEntity>(output, odataProperties.NextLink, odataProperties.TotalCount);
调用 GET API 时出现以下异常:
无法将“TableOneEntity”的 ODataQueryOptions 应用于 IQueryable 'TableTwoEntity'。
如何将相同的“选项”应用于 TableTwoDbSet ?
【问题讨论】:
【参考方案1】:管道会将 URL 转换为精确到一个 EDM 实体类的转换。所以简短的回答是你不能按照你正在做的事情做你想做的事情。但是,您可以做的是创建一个复合类(如果您使用的是 EF,则使用视图):
class Base
[Key]
public int ID;
public string Name;
public string Gender;
public string Comment;
[Table("T1")]
class TableOneEntity : Base
[Table("T2")]
class TableTwoEntity : Base
// extra columns from T2
public string Country;
public string City;
[Table("V1")] // which is a view containing columns from Base, T1 and T2.
class CompositeEntity : Base
// extra columns from T1
.....
// extra columns from T2
public string Country;
public string City;
那么你可以这样做:
[EnableQuery(PageSize = 100)] // For server-driven paging -- recommended but not obligatory
public IHttpActionResult GetTableResult()
return appDbCtx.Composite;
请记住将您的复合类添加到 EDM(通常在 WebApiConfig.cs 中)。就是这样。 OData 管道将为您完成所有其余工作。
编辑:
事实上,你可以通过使用开放类型来做你想做的事情。见http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-v4/use-open-types-in-odata-v4。但是,我怀疑复合类/视图在您的情况下会是更简单的选择。
【讨论】:
【参考方案2】:我通常会引用OData WebApi nuget package。
然后,对于控制器,添加 Queryable 属性并将您的集合返回为 Queryable 就完成了,只需将 OData 查询选项添加到您的调用中。
很酷的部分是,如果您使用的是 EF,那么所有过滤器和约束都会一直传递到 DB 查询。
public class MyController : ApiController
// Add the queryable attribute
[Queryable]
IQueryable<stuff> Get()
...
...
return myStuff.AsQueryable();
你可以像这样使用它:
http://www.blabla.bla/api/v1/stuff?$top=10&$skip=20&$orderby=name
--- 给你第 20 页,共 10 行,按名称排序。
请参阅OData conventions 以获得良好的参考:
【讨论】:
我的 ODataQueryOptions 也有分页.....会提供 Queryable 属性支持分页结果吗? 是的,它会的。只要您使用的是 OData 4。 使用分页示例更新答案 但是如果我只返回 IQueryable,客户如何知道下一个链接和总数。为此,我使用了 PageResult。 在传入的查询中包含 $count=true,管道将返回该元数据以及您的结果。以上是关于如何将 ODataQueryOptions<T> 应用于 IQueryable<X>的主要内容,如果未能解决你的问题,请参考以下文章
在 ASP.NET Web API 控制器的 nunit 测试中实例化新的 System.Web.Http.OData.Query.ODataQueryOptions
如何获取 OData 可查询 Web API 端点过滤器并从 DTO 对象映射它?