如何实例化 ODataQueryOptions

How to Instantiate ODataQueryOptions

我有一个可用的(简化的)ODataController,方法如下。

public class MyTypeController : ODataController
{
  [HttpGet]
  [EnableQuery]
  [ODataRoute("myTypes")]
  public IQueryable<MyType> GetMyTypes(ODataQueryOptions<MyType> options)
  {
    return _repo.myResultsAsQueryable();
  }
}

我希望能够从服务器调用此方法,为此我需要实例化一个 ODataQueryOptions,它需要一个 ODataQueryContext.

有一些示例说明如何执行此操作(例如,here and here) but they all seem to reference a previous version of OData. The ODataQueryContext 构造函数当前需要第三个参数(ODataPath 路径),我能找到的任何示例中均未提及。

编辑: @snow_FFFFFF,这里有更多上下文......我意识到我可以通过 HttpClient 简单地使用 OData 端点,但我想像你说的那样直接与 IQueryable 交互。

问题是我正在开发的应用程序允许用户创建过滤器(如复杂的搜索引擎),其他用户可以将其保存并稍后调用。从 JS 客户端,他们只需按 id 查找过滤器,然后对 OData 端点发出查询,并将过滤器应用于查询字符串。这在客户端非常有效,但我希望也能在服务器端做类似的事情。

这是我想要做的,但我如何实例化 ODataPath 参数?

public IQueryable<MyType> FilterMyTypes(int filterID)
{
  // lookup filter by filterID from db...
  filter = "$filter=Status eq 1"; // for example...

  ODataPath path = // but how can I get the path!!!
  new ODataQueryContext(edmModel, typeof(MyType), path); 

  var uri = new HttpRequestMessage(HttpMethod.Get, "http://localhost:56339/mytypes?" + filter);
  var opts = new ODataQueryOptions<MyType>(ctx, uri);

  var results = new MyTypeController().GetMyTypes(opts);
}

它的另一个应用是支持动态分组,如下所示:

[HttpGet]
[Route("myTypes/{filterID:int}/groupby/{groupByFieldName}")]
public IHttpActionResult GroupMyTypes(int filterID, string groupByFieldName)
{
  // For example: get all Active MyTypes and group by AssignedToUserID...

  // Get the results of the filter as IQueryable...
  var results = FilterMyTypes(filterID);

  // group on groupByFieldName
  var grouped = results.GroupBy(x => GetPropertyValue(x,groupByFieldName));

  // select the groupByFieldName and the count
  var transformedResults = grouped.Select(g => new { g.Key, Count = g.Count() });

  return Ok(transformedResults);
}

您的 odata 控制器正在为您的数据提供 HTTP 接口,您不应该通过 HTTP 访问它(即使是从服务器)?这里有生成odata客户端代码的VS插件:

https://visualstudiogallery.msdn.microsoft.com/9b786c0e-79d1-4a50-89a5-125e57475937

或者,如果您在同一个项目中执行此操作,为什么不使用 return 可以从您的代码或控制器调用的 IQueryable 的通用方法?

更新:基于原始问题中的更多信息:

如果您在控制器方法中定义了 ODataQueryOptions,它将允许您解析调用该方法的格式良好的 Odata 查询。我在需要翻译部分 odata 查询时使用了它,因为我需要查询多个数据源以 return 最终结果。

听起来你想要一些带有非 odata 参数和选项的东西。为此,您可能需要查看自定义操作和/或函数(如果您只是 returning 数据,可能是一个函数):

http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-v4/odata-actions-and-functions

更新#2:在更详细的阅读之后,我想我没有理解你的观点——我没有答案,但我会尝试一下。你不能只改造 URL 本身(而不是实例化查询选项吗?

更新#3:我想你很难让它认为它正在收到一个 odata 请求……那不是一个真正的 odata 请求.回到我原来的回答中提到的第二个选项——为什么不是你可以使用的通用方法和 odata 控制器可以使用的——像这样:

// some sort of helper class
public class HelperObject
{
    public static IQueryable<MyType> GetGroupedValues(int filterID, string groupByFieldName)
    {
        // all your code/logic here
    }
}

// your odata controller uses the helper
[HttpGet]
[Route("myTypes/{filterID:int}/groupby/{groupByFieldName}")]
public IHttpActionResult GroupMyTypes(int filterID, string groupByFieldName)
{
    return Ok(HelperObject.GetGroupedValues(filterID, groupByFieldName));
}

// ... and so does your other code that wants to do the same thing
var x = HelperObject.GetGroupedValues(filterID, groupByFieldName);

当然可以。 ODataPath 是一个 ODataPathSegment 列表,它应该跟在 OData Uri spec.

之后

在Web API OData中,很容易实例化一个ODataPath,例如:

IEdmModel model = GetEdmModel(); 
IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet(setName); 
ODataPath path = new ODataPath(new EntitySetPathSegment(entitySet)); 

上面的path遵循OData规范,它的odata模板为:

~/entityset

更多测试用例(代码)可以找到here