OData-v4 — работа с коллекцией сущностей, а затем выполнение функции

В моем контроллере ODATA-v4 у меня есть следующий код:

var fn = reportModelBuilder.EntityType<CurrentTestResult>()
         .Collection.Function("Breakdown").Returns<int>();

В CurrentTestResultController.cs у меня обманчиво просто:

[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
[HttpGet]
public IHttpActionResult Breakdown()
    {
    var count = dataService.GetAll()
                .Select(x => x.TestResultTypeId)
                .Distinct()
                .Count();

    return Ok(count);
    }

По сути, для всех сущностей CurrentTestResult в коллекции он возвращает отдельные TestResultTypeId, встречающиеся в наборе. (Это тривиальная операция, но я упростил реальный сценарий, который намного сложнее)

Это было легко сделать, но я не могу сначала отфильтровать коллекцию CurrentTestResult, с которой он должен работать.

Этот запрос, который по умолчанию работает со всеми объектами CurrentTestResult

localhost/app/odatareport/CurrentTestResult/Default.Breakdown

возвращается

{
@odata.context: "http://localhost/app/odatareport/$metadata#Edm.Int32",
value: 5
}

(Правильный результат, есть 5 различных типов)

Однако этот запрос, который пытается сначала просто отфильтровать его, терпит неудачу.

localhost/app/odatareport/CurrentTestResult/Default.Breakdown?$top=2

возвращается

{
error: {
code: "",
message: "The query specified in the URI is not valid. The requested resource is not a collection. Query options $filter, $orderby, $count, $skip, and $top can be applied only on collections.",
innererror: {
message: "The requested resource is not a collection. Query options $filter, $orderby, $count, $skip, and $top can be applied only on collections.",
type: "Microsoft.OData.ODataException",
stacktrace: 
" at System.Web.OData.EnableQueryAttribute.ValidateSelectExpandOnly(ODataQueryOptions queryOptions) at System.Web.OData.EnableQueryAttribute.ExecuteQuery(Object response, HttpRequestMessage request, HttpActionDescriptor actionDescriptor, ODataQueryContext queryContext) at System.Web.OData.EnableQueryAttribute.OnActionExecuted(HttpActionExecutedContext actionExecutedContext)"
     }
  }
}

Насколько я понимаю конвейер ODATA, почему это не работает, имеет смысл. Метод контроллера вернет IQueryable, а затем будут применены фильтры ODATA $filter, $top и т. д.

Я хотел бы, чтобы функция работала с набором, который уже был отфильтрован.

Возможно ли то, что я пытаюсь сделать?

Я понимаю, что в самом методе Breakdown есть .GetAll(), но должен быть способ применить фильтрацию перед методом -

Иначе все это совершенно бессмысленно...


person Matt    schedule 27.09.2017    source источник


Ответы (1)


Два варианта:

1) ODATA имеет конечную точку $count (см. эту, но есть две формы $count - конечная точка api/collection/$count и параметр системного запроса api/collection?$count=true; вам нужна конечная точка), которая возвращает количество коллекции (которую можно отфильтровать с помощью EnableQuery). Рассматривайте свою функцию как любой другой метод сбора GET и возвращайте запрос, который вы хотите подсчитать (в данном случае, отдельный TestResultTypeId), а затем просто попросите клиента запросить его $count конечную точку.

2) определите параметр ODataQueryOptions<T> для вашего метода действия и примените параметры вручную:

public IHttpActionResult Get( ODataQueryOptions<CurrentTestResult> queryOptions )
{
    // base query with ODataQueryOptions applied
    var query = queryOptions.ApplyTo( dataServcie.GetAll() ) 
        as IQueryable<CurrentTestResult>;

    // get distinct TestResultTypeId's and then count
    var count = query.Select(x => x.TestResultTypeId)
            .Distinct()
            .Count();

    return Ok( count );
}

Я сейчас мобилен, поэтому не могу протестировать, но это должно быть достаточно близко (если не точно), чтобы доставить вас туда, куда вам нужно. Пожалуйста, дайте мне знать, если есть какие-либо проблемы, и я обновлю ответ.

person Moho    schedule 29.09.2017
comment
Это действительно очень близко - у меня все еще есть проблема - я сделал, как вы сказали - когда я прохожу код, он применяет параметры - однако в клиенте я получаю следующее: imgur.com/a/dU32b - person Matt; 03.10.2017
comment
Ничего, я забыл удалить атрибут AllQueryOptions - еще раз спасибо! - person Matt; 03.10.2017
comment
Отлично, без проблем - person Moho; 03.10.2017