Skip to content

Latest commit

 

History

History
 
 

Beef.Data.OData

Beef.Data.OData

NuGet version

Adds additional capabilities extending Simple.OData.Client that standardises and simplifies usage of OData endpoints for Beef.


Client

Simple.OData.Client is being used as the OData client as it is lightweight and completely decoupled from the underlying OData endpoint. It has a simple, albeit rich, capability that fits nicely into the approach and philosophy of Beef's data source adapters.

To encapsulate the OData access the OData or ODataBase is inherited to enable. Additional capabilities are added by Beef to simplify usage, and provide a similar experience to the other data source adapters.

The following demonstrates the usage:

public class TestOData : OData<TestOData>
{
    public TestOData(Uri baseUri) : base(baseUri) { }
}

Considered, but rejected

Microsoft's OData Connected Service was considered as this certainly adds a level of acceleration by providing an early-bound, strongly-typed, client code-generated from the OData metadata endpoint. The two issues that were cause for exclusion related to:

a) It is all or nothing, in that all entities, properties, operations, etc. are generated from the $metadata even where only a subset is required. This is an issue where there any many 100s/1000s as is the case with the likes of Microsoft Dynamics 365. There is a PBI in their backlog that states they are considering the addition of entity selection in the future.

b) Where only interested in a subset of the properties for an entity there is no simple way to only reference those, more specifically for create and update (patch) where there is a requirement for all properties to be provided.

This may be added, as an alternative in the future, where there is demand.

Mapping

A key feature is the mapping of a .NET entity to/from an OData-oriented .NET model (these can be the same). The ODataMapper will enable:

  • Property to/from mapping, including naming differences.
  • Property to/from data type conversions.
  • Entity to/from one or more property mappings.

Also, specific mappings can be configured to only be performed when performing a specific operation type; e.g. Create or Update, etc.

The following demonstrates the usage:

public partial class ODataMapper : ODataMapper<TripPerson, Model.Person, ODataMapper>
{
    /// <summary>
    /// Initializes a new instance of the <see cref="ODataMapper"/> class.
    /// </summary>
    public ODataMapper()
    {
        Property(s => s.Id, d => d.UserName).SetUniqueKey(false);
        Property(s => s.FirstName, d => d.FirstName);
        Property(s => s.LastName, d => d.LastName);
        ODataMapperCtor();
    }
    
    /// <summary>
    /// Enables the <see cref="ODataMapper"/> constructor to be extended.
    /// </summary>
    partial void ODataMapperCtor();
}

Operation arguments

The ODataArgs provides the required Collection operation arguments. As a general rule the ODataArgs is created from the ODataMapper:

Property Description
CollectionName The OData Collection name; where null will infer from the model Type name.
Paging The paging configuration (used by Query operation only).
NullOnNotFoundResponse Indicates that a null is to be returned where the response has an HttpStatusCode.NotFound on a Get.

The following demonstrates the usage:

var args1 = ODataMapper.Default.CreateArgs("Persons");
var args2 = ODataMapper.Default.CreateArgs("Persons", paging);

CRUD

The primary data persistence activities are CRUD (Create, Read, Update and Delete) related; ODataBase enables:

Operation Description
GetAsync Gets the entity for the specified key where found; otherwise, null (default) or NotFoundException depending on the corresponding ODataArgs.NullOnNotFoundResponse.
CreateAsync Creates the entity.
UpdateAsync Updates the entity.
DeleteAsync Deletes the entity. Given a delete is idempotent it will be successful even where the entity does not exist.

Query

More advanced query operations are enabled via by the ODataQuery which further extends on the LINQ-like capabilities provided by the Simple.OData.Client. This supports an overload where a query Func can be added to simplify the likes of filtering, etc. where needed:

Operation Description
SelectFirst Selects the first item.*
SelectFirstOrDefault Selects the first item or default.*
SelectSingle Selects a single item.*
SelectSingleOrDefault Selects a single item or default.*
SelectQuery Select multiple items and either creates, or updates an existing, collection. Where the corresponding ODataArgs.Paging is provided the configured paging, and optional get count, will be enacted.

* These are provided for use versus than the default IQueryable equivalents as they will only internally page one or two items accordingly to minimise query and data costs.


Filtering

The IBoundClient provides LINQ-like filtering (although Filter is used instead of Where); Beef extends the capabilities as follows:

Operation Description