OdataToEntity – an easy way to create .Net Core OData services

Total: 21 Average: 4.4

When .Net Core was released, the old version of OData ASP.NET Web API turned out to be incompatible with the new platform. This fatal flaw allowed me to create my OData implementation on the .Net Core platform. After the creative rethinking of the previous implementation, I came to an understanding that it suffered from a complicated design with a lot of unnecessary abstractions. An idea to create an easy-to-use library that requires minimal coding came into my mind. I would like to present you OdataToEntity, the library for creating OData services without code writing; the only thing needed is data access context.

As a consequence, to simplify the design of the API, it was decided not to use interfaces in the code, while the library has a full test coverage. To reduce external dependencies, the library is unbound from HTTP, which allows implementing OData on top of any transport. This engineering marvel is assembled for Framework 4.8 or .Net Core 3.1 and uses Microsoft.OData.Core 7.6.1. The following data contexts are supported:

  1. Entity Framework 6.4
  2. Entity Framework Core 3.1
  3. Linq2Db

How it works

The main idea of the project is the translation of OData queries into an expression tree, which is then transferred to the appropriate data access adapter.

To isolate the library from various ORM APIs, the OdataToEntity.Db.OeDataAdapter “data access adapter” abstract class is used. Each context implements its successor from this class (Ef6: OeEf6DataAdapter, EfCore: OeEfCoreDataAdapter, Linq2Db: OeLinq2DbDataAdapter).

Based on the data model, the OData Entity Data Model (EDM) is constructed to describe the data provided by your service. The EDM model is required for the ODataLib library to parse the query string. If the user entities are marked with attributes (System.ComponentModel.DataAnnotations), then the model can be built using a standard method suitable for all data providers.

If the Entity Framework context is used and the “Fluent API” (without using attributes) is used to describe the entities:

Entity Framework Core

Entity Framework 6

Build from multiple data contexts

The library can be used for reading and editing data.

In the read mode, an OData query is sent to the library input, it is parsed using the Microsoft.OData.Core (ODataLib) into the ODataLib representation, which is translated into the standard expression tree. The query is parameterized (i.e. constant expressions are replaced with variables) and then passed to the data access adapter. The adapter translates the standard expression tree into more specific one that is applicable in this data context. This creates a context that executes the query against the database, and the resulting entities are serialized in the OData JSON format.

In the editing mode, the model entities serialized in the OData JSON format are sent to the library input. With the help of ODataLib, data in the model entities are deserialized, added to the data access context, and stored in the database. Fields computed on the database side are returned to the client. “Batch change set” – batch addition, deletion, change of entities is supported. Editing of tables that describe the tree-like data structures (self-referencing table) is supported as well. A data context similar to DbContext Entity Framework allowing you to edit the object graph was implemented for Linq2Db.

Supported Query Types

  1. $apply (filter, groupby, aggregate (average, count,  virtual property $count, countdistinct, max, min, sum))
  2. $count
  3. $filter
  4. $orderby
  5. $select
  6. $skip
  7. $top
  8. $compute
  9. $skiptoken
  10. lambda any
  11. lambda all

Supported functions

  1. cast
  2. ceiling
  3. concat
  4. contains
  5. day
  6. endswith
  7. floor
  8. fractionalseconds
  9. hour
  10. in
  11. indexof
  12. length
  13. minute
  14. month
  15. round
  16. second
  17. startswith
  18. substring
  19. tolower
  20. toupper
  21. trim
  22. year

Example of use

The following data model is used in the tests and examples

The sample OData query consists of only five lines:

An example of storing new entities in the database also consists of five lines:

An example of executing a stored procedure

To specify a procedure name that differs from a method name in c#, you can use the attribute

Other examples can be found in the test folder

Server-Driven Paging

To use responses that include only a partial set of the items identified by the request indicate maximum page size through the invoke method OeRequestHeaders.SetMaxPageSize(int maxPageSize). The service serializes the returned continuation token into the $skiptoken query option and returns it as part of the next link annotation (@odata.nextLink) to the client. If request returns result set sorted by nullable property, should set OeDataAdapter.IsDatabaseNullHighestValue (SQLite, MySql, Sql Server set false, for PostgreSql, Oracle set true).

To use server side paging in expanded to-many navigation properties, should invoke method OeRequestHeaders.SetNavigationNextLink(true)

A function specific to the Entity Framework Core

For the Entity Framework Core provider, there is the ability to cache queries, which on existing tests allows you to increase the performance up to two times. The cache key is a parsed OData query with remote constant values, and the value is a delegate accepting the data context and returning the query result. This allows to exclude the stage of building the data query itself (IQueryable). To use this feature, you need to use the constructor OeEfCoreDataAdapter(DbContextOptions options, Db.OeQueryCache queryCache)

For use pooling (DbContextPool) in Entity Framework Core create instance OeEfCoreDataAdapter use constructor with DbContextOptions parameter.

Source code structure

The source code is divided into two parts: the source folder contains the library itself and assemblies to access various data sources, and the test folder contains tests and code samples.

Files of solutions are located in the sln folder.

The library itself is located in the source/OdataEntity project.

Adapter to the Entity Framework 6.2 context – in source/OdataToEntity.Ef6.

Adapter to the Entity Framework Core context – in source/OdataToEntity.EfCore.

Adapter to the Linq2Db context – in source/OdataToEntity.Linq2Db.


Entity Framework Core in-memory database test/OdataToEntity.Test

Entity Framework Core SQL Server test/OdataToEntity.Test.EfCore.SqlServer

Entity Framework Core PostgreSql test/OdataToEntity.Test.EfCore.PostgreSql

Entity Framework 6 SQL Server test/OdataToEntity.Test.Ef6.SqlServer

Linq2Db SQL Server test/OdataToEntity.Test.Linq2Db

Examples of queries can be found in tests

Tested OData requests



HTTP сервис test/OdataToEntityCore.Asp/OdataToEntity.Test.AspServer

HTTP Mvc сервис test/OdataToEntityCore.Asp/OdataToEntity.Test.AspMvcServer

Microsoft.OData.Client for HTTP service test/OdataToEntity.Test.AspClient

Microsoft.OData.Client and WCF servers source/OdataToEntity.Test.Wcf

An example contract of a Wcf service that works with Microsoft.OData.Client

The script for creating an SQL Server database for tests test\OdataToEntity.Test.EfCore.SqlServer\script.sql

The script for creating an SQL Server database for tests test\OdataToEntity.Test.EfCore.PostgreSql\script.sql

Source code

Nuget packages


Maxim Voronov

Maxim started as a C# developer in 2007. Сore competencies: backend, databases (ADO .Net, Entity Framework, Linq2Db), and services (WCF, Asp.Net, OData).
Maxim Voronov

Latest posts by Maxim Voronov (see all)