XData Model
All the data exposed by the XData server is specified in the XData Model
represented by the class TXDataAureliusModel (declared in unit
XData.Aurelius.Model
). The XData Model describes all the types (classes)
and properties provided by the server, among other info.
The XData Model describes all information the server provides, which are used to create endpoints and to describe types and data received or returned by the server. This allows additional flexibility, like for example, having a property name in XData to be different than the property name in the mapped Aurelius class, or manually adding a service operation without relying on ServiceContract/ServiceImplementation attributes.
The XData model in summary, describes the service operations available, the Aurelius entities published from the CRUD endpoints, and the types it understands.
The following topics explain in more details what the XData model is about.
Entity Model Concepts
This topic describes the main concepts used in the XData Model:
Services/Contracts
Services (specified by contracts) are a set of service operations, actions that are executed based on a client request and HTTP method. The service contracts are defined by service interfaces (contracts) and implemented by the server. For more information, see service operations.
Enum Type
Enum types are named scalar, primitive types that contain a list of name/value pairs which indicates its valid values. For example, the enum type "TSex" might have two name/value pairs: First is name "Male", with value 0, and second is name "Female", with value 1. Simple properties which types are enum types can only receive such values.
Concepts related to Aurelius CRUD Endpoints
Entity Set (the CRUD Endpoint itself)
An entity set is a logical container for instances of an entity type (Aurelius entities) and instances of any type derived from that entity type. It can also be though as a collection of entities of a specified entity type. Thus, each entity set is associated with a entity type. Entity sets could be though as equivalent of a table in a database, but it's not exactly the same, since conceptually you might have different entity sets for the same entity type (although it's not often used). By default the name of the entity set is the name of the entity type associated to it so an entity set "Customer" will provide list of entities of type "Customer". It might be confused that both have same names, but they have different concepts.
Entity Type
The Aurelius entity type relates to an entity in the same way as a class relates to an object in object-oriented programming. In other words, an entity type is the "class definition" used by XData to retrieve info about an entity it receives or provides. An entity type contain a list of properties, what of those properties are considered the primary key for the entity, etc.. The entity type is related to a Delphi class, and as such it also supports inheritance (an entity type can be inherited from another entity type). By default the name of entity type is the name of the class, with the "T" prefix removed (if any). For example, there might be an entity type named "Customer", related to class TCustomer, with simples properties "Name", "City" and navigation property "Country".
Simple Property
A simple property is a property of a scalar type, belonging to an entity type. A simple property can be of any primitive type as integer, boolean, string, etc., or enum types, and can have several facets indicating for example if the property is nullable, or its maximum length. For example, an entity type "TCustomer" can have a simple property "Name" of type string, and a simple property "Sex" of enum type "TSex".
Navigation Property
A navigation property is a property that represents a relationship between two entity types. It might relate to a single entity or a collection of other entities. It's the equivalent of an association in Aurelius mapping, or a foreign key in a database definition. A navigation property has a target property which points to another entity type. For example, an entity type "TOrder" might have a navigation property named "Customer" which target type is the "TCustomer" entity type.
Using TXDataModelBuilder
XData server uses XData model to specify the data it will publish through the Rest/Json interface. To work properly, the server module (TXDataServerModule object) needs a XData model, represented by a TXDataAureliusModel to work properly.
However, you can create the TXDataServerModule without explicitly providing an entity model. In this case, the server will create one internally, based on the default TMappingExplorer, using the conventions of service operations and Aurelius CRUD endpoints. That's the most straightforward and common way to use it, and you will rarely need to create an XData model yourself.
In the case you want to build your own model and create a server based on it (for example, when you don't want classes and fields to have their "T" and "F" prefix removed from their names), you can do it using the TXDataModelBuilder.
The following example creates a model based on the default mapping explorer, however it sets properties UseOriginalClassNames and UseOriginalFieldNames to true to avoid the model builder to remove the "T" prefix from class names when naming entity types, and remove "F" prefix from field names when naming properties and navigation properties.
uses
{...}, XData.Aurelius.ModelBuilder, XData.Aurelius.Model,
XData.Server.Module, Aurelius.Mapping.Explorer;
var
Builder: TXDataModelBuilder;
Model: TXDataAureliusModel;
Explorer: TMappingExplorer;
Module: TXDataServerModule;
begin
// model uses a TMappingExplorer instance with Aurelius mapping
// this example doesn't explain how to obtain one, please refer to Aurelius documentation
Explorer := TMappingExplorer.DefaultInstance;
Model := TXDataAureliusModel.Create(Explorer);
try
Builder := TXDataModelBuilder.Create(Model);
try
Builder.UseOriginalClassNames := true;
Builder.UseOriginalFieldNames := true;
Builder.Build;
finally
Builder.Free;
end;
except
Model.Free; // destroy the model in case an error occurs
raise;
end;
// create the module using the created model.
Module := TXDataServerModule.Create(MyServerUrl, MyConnectionPool, Model);
end;
When adding service operations to the model, the model builder will only take into consideration those service interfaces that belong to the same model of the TMappingExplorer instance you are using. For example, if your TMappingExplorer represents the model "Sample", only service contracts marked for the "Sample" model will be included in the entity model.
You can use the methods and properties of TXDataModelBuilder to better define your XData Model:
TXDataModelBuilder class
Declared in Unit XData.Aurelius.ModelBuilder
.
Properties
Name | Description |
---|---|
UseOriginalClassNames: Boolean | By default XData removes the leading "T" of the class name to define the entity set name. So a class TCustomer will correspond to the entity set "Customer". If you don't want this behavior and wants the entity set name to be exactly the name of the class, set this property to true. |
UseOriginalFieldNames: Boolean | By default XData removes the leading "F" of a mapped field name to define the property name of an entity type. So a field named "FName" will correspond to a property "Name" in JSON responses. If you don't want this behavior and wants the property name to be exactly the name of the field, set this property to true. |
UseOriginalContractNames: Boolean | By default XData removes the leading "I" of the interface name to define the url segment of a service operation. So an interface ITestService will correspond to a service URL which path segment will beign with "TestService". If you don't want this behavior and wants the service operation base URL to be exactly the name of the interface, set this property to true. |
Methods
Name | Description |
---|---|
function AddEntitySet(AClass: TClass): TXDataEntitySet | Creates a new entity set (CRUD endpoint) based on the class defined by AClass. The class must be an Aurelius entity. This will automatically create the entity type associated with the entity set. |
procedure AddService<T> | Adds a new service operation contract to the model. Example:Model.AddService<IMyService>; |
procedure RemoveEntitySet(AClass: TClass) | Use this to remove an entity set already created by the model. This is useful when you want to use the automatic creation of entity sets, based on Aurelius entities, but then you want to remove a few entity sets from the model. |
Multiple servers and models
You can create multiple XData servers (TXDataServerModule instances), at different addresses. This makes more sense if you use different entity models for each of those XData modules. It's very easy to do so in XData using a way similar to Aurelius multi-model design. When defining different models with different classes (and service operations), you can easily create different XData modules in a single server application.
To specify the different models in each server module, you just need to provide an instance of a TXDataAureliusModel that represents the desired entity model. And you can easily retrieve the correct instance by using the TXDataAureliusModel.Get class method, passing the model name to the function. The entity model will then only consider entity types and service operations that belongs to that model.
For example, the following code creates two different TXDataServerModule modules, using two different entity models:
XDataSampleModule := TXDataServerModule.Create('http://server:2001/tms/xdata/sample',
SampleConnectionPool, TXDataAureliusModel.Get('Sample'));
XDataSecurityModule := TXDataServerModule.Create('http://server:2001/tms/xdata/security',
SecurityConnectionPool, TXDataAureliusModel.Get('Security'));
HttpServer.AddModule(XDataSampleModule);
HttpServer.AddModule(XDataSecurityModule);
Note that this approach will filter all classes (entity types) belonging that specific model (for example, XDataSampleModule will only publish entity types which classes are marked with Model('Sample') attribute:
[Model('Sample')]
It will filter both service operations and Aurelius CRUD Endpoints according to the model name. So XDataSampleModule will only have services operations which service interfaces are marked with the Model('Sample') attribute.