Обычно OData и EF идут рука об руку, OData преобразует входящий HTTP-запрос в Выражение Linq-to-Entities, которое EF затем преобразует в выражение SQL.
tl;dr
Все ваши комментарии и наблюдения указывают на неправильную реализацию в вашем контроллере, это звучит подозрительно, как если бы вы следовали примеру, основанному на шаблоне репозитория, а не примерам на основе EF.
Передает ли конечная точка oData с EntityFramework мои параметры oData для выполнения перед моим запросом SQL?
Это именно то, для чего была разработана среда OData, но есть одно предостережение: вы должны настроить свои контроллеры таким образом, чтобы параметры могли передаваться через них.
Есть два механизма, которые позволяют этому случиться. Во-первых, ваш контроллер должен вернуть результат IQueryable<T>
(или вы должны передать IQueryable<T>
одному из согласованных обработчиков ответов). Во-вторых, вы не должны применять свои собственные выражения фильтра, которые могут противоречить параметрам, в противном случае вы можете привести к тому, что записи не будут возвращены.
Ниже приведен пример двух стандартных Get
конечных точек на контроллере OData, которые будут возвращать запрос Vehicle, который позволит передавать выражения _4 _, _ 5_ и $filter
:
[ODataRoute]
[HttpGet]
[OData.EnableQuery]
public IHttpActionResult Get(ODataQueryOptions<Vehicle> queryOptions)
{
return Ok(db.Vehicles);
}
[ODataRoute]
[HttpGet]
[OData.EnableQuery]
public IHttpActionResult Get([FromOdataUri] int key, ODataQueryOptions<Vehicle> queryOptions)
{
return SingleResultAction(db.Vehicles.Where(x => x.Id == key));
}
Если я вызову это со следующими параметрами запроса:
$filter=Make eq Holden and Model eq Commodore&$orderby=Year desc
тогда это будет преобразовано в запрос SQL, подобный этому:
(SELECT * будет развернут полностью)
DECLARE @make varchar(20) = 'Holden';
DECLARE @model varchar(20) = 'Commodore';
SELECT *
FROM Vehicle
WHERE Make = @make
AND Model = @model
ORDER BY Year DESC
Да, параметры тоже будут правильно параметризованы!
Этот простой контроллер также проходит через $expand
запрос и автоматически присоединяется к необходимым таблицам, нам вообще не нужно заранее знать или думать о потенциальных включаемых.
Фактически, если я добавлю $skip=5
и $top=2
, эти предложения также будут применены непосредственно к оператору SQL, и из базы данных будет возвращено не более 2 строк.
Есть два распространенных сценария, когда все эти автоматические магические переводы запросов и их передача через тупой джамбо нарушаются.
В методе контроллера (для коллекции или элемента) вы не возвращаете результат IQueryable
или иным образом выполнили запрос и разрешили его до IEnumerable
, а затем вы вернули его, возможно, вернув его обратно к IQueryable
.
- This tends to happen because when we start out we tend follow simple non EF based OData examples, they usually follow a repository pattern because it is simple to explain the model, example data and implementation in a single page of code.
Объявление общественной службы: не пытайтесь использовать шаблон репозитория для обертывания модели и контекста EF, почти все преимущества EF будут потеряны. EF - это шаблон «Единица работы», OData предназначена для работы с ним напрямую.
Следующая реализация контроллера НЕ будет передавать параметры запроса в базу данных, _16 _, _ 17 _, _ 18 _, _ 19 _, _ 20_ будет по-прежнему применяться, если это возможно, но только после извлечения всех записей в память в первую очередь. :
return Ok(db.Vehicles.ToList());
$expand
не будет применяться, или, скорее, это приведет к NULL
связанным записям.
Другая распространенная проблема возникает после Действия, когда запись данных (или записи) была обработана, если мы хотим автоматически поддерживать весь диапазон параметров запроса, нам снова нужно убедиться, что мы возвращаем выражение IQueryable
, которое запросы от DbContext
. Если выражение IQueryable
, но запрашивает только то, что уже находится в памяти, то, например, $expand
и $filter
могут применяться только к тем данным, которые уже загружены.
SingleResultAction
is a good helper method for returning an IQueryable
that has been scoped toa single item, but it will still allow the full range of QueryOptions to be applied.
person
Chris Schaller
schedule
22.03.2021