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

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.6.2 or .Net Core 1.2 and uses Microsoft.OData.Core 7.2. The following data contexts are supported:

  1. Entity Framework 6.1
  2. Entity Framework Core 1.2
  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

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, countdistinct, max, min, sum))
  2. $count
  3. $filter
  4. $orderby
  5. $select
  6. $skip
  7. $top
  8. lambda any
  9. lambda all

Supported functions

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

For Entity Framework Core, there is the ability to cache queries, which allows increasing the access speed up to two times on the existing tests. 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 excluding the stage of building the data query itself (IQueryable).

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.1 context – in source/OdataToEntity.Ef6.

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

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

Tests:

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

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

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

 

Examples:

HTTP service test/OdataToEntityCore.Asp

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

Microsoft.OData.Client and WCF servers source/OdataToEntity.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

Source code

Nuget packages

 

Maxim Voronov

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)

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).