Запрос подключенной службы ODataV4 с помощью LINQ — получение последней записи из таблицы

Я пытаюсь запросить мой веб-сервис OData из приложения С#.

Когда я делаю следующее:

      var SecurityDefs = from SD in nav.ICESecurityDefinition.Take(1) 
                   orderby SD.Entry_No descending 
                   select SD;

я получаю исключение, потому что .top() и .orderby не должны использоваться вместе.

Мне нужно получить последнюю запись в наборе данных и только последнюю.

Цель состоит в том, чтобы получить последний использованный номер записи в книге, а затем продолжить создание новых записей, увеличивая найденный номер записи.

Кажется, я не могу найти в Интернете ничего, что объясняет, как это сделать.

Очень важно, чтобы сервис возвращал только последнюю запись из фида, так как скорость имеет первостепенное значение в этом решении.

1 ответ

я получаю исключение, потому что .top() и .orderby не должны использоваться вместе.

Где ты это прочитал? В целом .top()или же .Take()следует использовать ТОЛЬКО в сочетании с .orderby(), в противном случае не гарантируется, что извлекаемая запись будет повторяемой или предсказуемой.

Вероятно, проблема здесь заключается в смешивании синтаксиса запроса и свободного выражения, что является допустимым, но вы должны понимать порядок приоритета.
Ваш синтаксис принимает 1 запись, а затем применяет порядок сортировки... вам может быть проще начать с такого запроса :

      // build your query
var SecurityDefsQuery = from SD in nav.ICESecurityDefinition 
                        orderby SD.Entry_No descending 
                        select SD;
// Take the first item from the list, if it exists, will be a single record.
var SecurityDefs = SecurityDefsQuery.FirstOrDefault();
// Take an array of only the first record if it exists
var SecurityDefsDeferred = SecurityDefsQuery.Take(1); 

Это можно выполнить в одной строке, используя скобки, но вы можете видеть, что запрос одинаков в обоих случаях, SecurityDefsв данном случае один ICESecurityDefinitionтипизированная запись, где как SecurityDefsDeferredявляется IQueryable<ICESecurityDefinition>который имеет только одну запись.

Если вам нужна только сама запись, вам нужен один вкладыш:

      var SecurityDefs = (from SD in nav.ICESecurityDefinition 
                    orderby SD.Entry_No descending 
                    select SD).FirstOrDefault();

Вы также можете выполнить тот же запрос, используя беглую нотацию:

      var SecurityDefs = nav.ICESecurityDefinition.OrderByDescending(sd => sd.Entry_No)
                                            .FirstOrDefault();

В обоих случаях, .Take(1)или .top() реализуется через . Вы указали, что скорость важна, поэтому используйте .First()или же .FirstOrDefault()вместо .Single()или же .SingleOrDefault()потому что отдельные варианты на самом деле будут запрашивать .Take(2)и выдаст исключение, если он вернет 1 или не вернет никаких результатов.

Варианты OrDefault для обоих этих запросов не повлияют на производительность самого запроса и должны иметь незначительное влияние на ваш код, используйте тот, который подходит для вашей логики, которая использует возвращенную запись, и если вам нужно обработать случай, когда есть нет существующей записи.

Если возвращаемая запись имеет много столбцов, и вас интересует только значение столбца, то, возможно, вам следует просто запросить это конкретное значение:

Выражение запроса :

      var lastEntryNo = (from SD in nav.ICESecurityDefinition 
                   orderby SD.Entry_No descending 
                   select SD.Entry_No).FirstOrDefault();

Плавное выражение :

      var lastEntryNo = nav.ICESecurityDefinition.OrderByDescending(sd => sd.Entry_No)
                                           .Select(sd => sd.Entry_No)
                                           .FirstOrDefault();

Если скорость имеет первостепенное значение , рассмотрите возможность предоставления конкретной пользовательской конечной точки в службе, чтобы либо обслуживать запись, либо вообще не обрабатывать «Entry_No» в клиенте, сделайте это заданием кода, который получает данные от клиента и вычисляет их. в момент вставки записей.

Ускорение выполнения запроса — это не серебряная пуля, которую вы, возможно, ищете. Даже если это сильно оптимизировано, ваш текущий шаблон означает, что Xнесколько клиентов могут вызвать службу, чтобы получить текущее значение , что означает, что все они начнут увеличиваться с одного и того же значения.

Если вы ДОЛЖНЫ увеличить значение от клиента , вам следует подумать о добавлении пользовательской конечной точки в службу, чтобы просто вернуть Next для использования. Это должно быть оптимистичным , означающим, что вас не волнует, если Entry_Noфактически используется в конце, но вы можете реализовать конечную точку так, чтобы каждый вызов увеличивал поле в базе данных и возвращал следующее значение.

Это немного выходит за рамки вашего первоначального поста, но SQL Server теперь поддерживает последовательности , которые формализуют этот тип логики с точки зрения базы данных и схемы, использование последовательности упрощает управление этими типами приращений от клиента, потому что мы больше не полагаемся на то, что результаты обновлений данных будут зафиксированы в таблице до того, как клиент сможет увеличить следующую запись. (это то, что ваш TOP, Order By Descрешение пытается сделать.

Другие вопросы по тегам