Customizing the Entity Model
OData and the Entity Framework are based on the same underlying concept for mapping the idea of an Entity with its representation in the database. That “mapping” layer is called the Entity Data Model, or EDM for short. Part of the beautiy of RESTier is that, for the majority of API builders, it can construct your EDM for you automagically. But there are times where you have to take charge of the process. And as with many things in RESTier, the intrepid developers at Microsoft provide you with two ways to do so. The first method allows you to completely relpace the automagic model construction with your own, in a manner very similar to Web API OData. The second method lets RESTier do the initial work for you, and then you manipulate the resulting EDM metadata. Let’s take a look at how each of these methods work.ModelBuilder Takeover
There are several situations where you are likely going to want to use this approach to create your Model. For example, if you’re migrating from an existing Web API OData v3 or v4 implementation, and needed to customize that model, you will be able to copy/paste your existing code over, with just a few small changes. If you’re building a new model, but you’re using Entity Framework Model First + SQL Views, then you’ll likely need to define a primary key, or omit the View from your service. With the Entity Framework provider, the model is built with the ODataConventionModelBuilder. To understand how this ModelBuilder works, please take a few minutes and review that documentation.Example
Api class is required because the provider will take over to build the model instead.
But what the provider does behind the scene is similar.
Extend a model from Api class
TheRestierModelExtender will further extend the EDM model passed in using the public properties and methods defined in the
Api class. Please note that all properties and methods declared in the parent classes are NOT considered.
Entity set
If a property declared in the Api class satisfies the following conditions, an entity set whose name is the property name
will be added into the model.
- Public
- Has getter
- Either static or instance
- There is no existing entity set with the same name
- Return type must be
IQueryable<T>whereTis class type
Api class satisfies the following conditions, a singleton whose name is the property name
will be added into the model.
- Public
- Has getter
- Either static or instance
- There is no existing singleton with the same name
- Return type must be non-generic class type
RestierModelExtender follows the rules below to add navigation property bindings after entity
sets and singletons have been built.
- Bindings will ONLY be added for those entity sets and singletons that have been built inside
RestierModelExtender. Example: Entity sets built by the RESTier’s EF provider are assumed to have their navigation property bindings added already. - The
RestierModelExtenderonly searches navigation sources who have the same entity type as the source navigation property. Example: If the type of a navigation property isPersonorCollection(Person), only those entity sets and singletons of typePersonare searched. - Singleton navigation properties can be bound to either entity sets or singletons.
Example: If
Person.BestFriendis a singleton navigation property, bindings fromBestFriendto an entity setPeopleor to a singletonBossare all allowed. - Collection navigation properties can ONLY be bound to entity sets.
Example: If
Person.Friendsis a collection navigation property. ONLY binding fromFriendsto an entity setPeopleis allowed. Binding fromFriendsto a singletonBossis NOT allowed. - If there is any ambiguity among entity sets or singletons, no binding will be added.
Example: For the singleton navigation property
Person.BestFriend, no binding will be added if 1) there are at least two entity sets (or singletons) both of typePerson; 2) there is at least one entity set and one singleton both of typePerson. However for the collection navigation propertyPerson.Friends, no binding will be added only if there are at least two entity sets both of typePerson. One entity set and one singleton both of typePersonwill NOT lead to any ambiguity and one binding to the entity set will be added.
Operation If a method declared in the
Api class satisfies the following conditions, an operation whose name is the method name will be added into the model.
- Public
- Either static or instance
- There is no existing operation with the same name
- Operation attribute’s EntitySet property is needed if there are more than one entity set of the entity type that is type of result defined. Take an example if two EntitySet People and AllPersons are defined whose entity type is Person, and the function returns Person or List of Person, then the Operation attribute for function must have EntitySet defined, or EntitySet property is optional.
- Function and Action uses the same attribute, and if the method is an action, must specify property HasSideEffects with value of true whose default value is false.
-
In order to access an operation user must define an action with
ODataRouteAttributein his custom controller. Refer to section 3.3 for more information.
Custom model extension
If users have the need to extend the model even after RESTier’s conventions have been applied, user can use IServiceCollection AddService to add a ModelBuilder after calling base.ConfigureApi(services).- User’s model builder registered before base.ConfigureApi(services) is called first.
- RESTier’s model builder includes EF model builder and RestierModelExtender will be called.
- User’s model builder registered after base.ConfigureApi(services) is called.
If InnerModelBuilder method is not called first, then the calling sequence will be different. Actually this order not only applies to the
IModelBuilder but also all other services.
Refer to section 4.3 for more details of RESTier API Service.