如何支持OData查询语法但返回非Edm模型

时间:2015-08-28 15:59:20

标签: entity-framework odata

将我的EF模型暴露给API似乎总是错误的。我希望我的API能够将自定义实体模型返回给调用者,但在后面使用EF。

所以我可能有PersonRestEntity和CRUD操作系统的控制器以及一个Person EF代码优先实体,后面是in和map值。

当我执行此操作时,我无法再使用以下内容在网址中允许~/people?$top=10

[EnableQuery]
public IQueryable<Person> Get(ODataQueryOptions<Person> query) { ... }

因为这会公开Person私有数据库实现。

我怎样才能吃蛋糕并吃掉它?

1 个答案:

答案 0 :(得分:7)

我发现了一种方法。诀窍不仅仅是从控制器返回IQueryable,因为您需要首先实现查询。这并不意味着将整个集合实现到RAM中,查询仍在数据库中运行,但通过显式应用查询并实现结果,您可以在此后返回映射实体。

定义此操作,指定DbSet实体类型:

public async Task<HttpResponseMessage> Get(ODataQueryOptions<Person> oDataQuery)

然后手动将查询应用于DbSet<Person>,如下所示:

var queryable = oDataQuery.ApplyTo(queryableDbSet);

然后使用以下命令运行查询并将结果转换为您公开公开的实体集合:

var list = await queryable.ToListAsync(cancellationToken);
return list
    .OfType<Person>()
    .Select(p => MyEntityMapper.MapToRestEntity(p));

然后您可以照常返回HttpResponseMessage列表。

就是这样,虽然显然实体之间的属性名称不匹配或者在任何一个类中都不存在,但是会出现一些问题,因此最好确保要包含在查询选项中的属性被命名两个实体都是一样的。

否则,我猜您可以选择不支持过滤器,只允许$top$skip并自行强加默认订单。这可以像这样实现,确保首先订购可查询的 ,然后跳过,然后跳到顶部。类似的东西:

IQueryable queryable = people
    .GetQueryable(operationContext)
    .OrderBy(r => r.Name);

if (oDataQuery.Skip != null)
    queryable = oDataQuery.Skip.ApplyTo(queryable, new System.Web.OData.Query.ODataQuerySettings());                

if (oDataQuery.Top != null)
    queryable = oDataQuery.Top.ApplyTo(queryable, new System.Web.OData.Query.ODataQuerySettings());

var list = await queryable.ToListAsync(operationContext.CreateToken());

return list
    .OfType<Person>()
    .Select(i => this.BuildPersonEntity(i));

更多信息:

如果您只是使用非通用ODataQueryOptions,那么

  

无法在控制器'人'上创建EDM模型作为'获取'操作   有一个返回类型'System.Net.Http.HttpResponseMessage',但没有   实现IEnumerable

其他错误会在不同情况下发生。