DevExpress ORM XPO is built upon several layers, each serving a specific purpose in the application’s data access and storage. In this article, we’ll discuss the main layers of XPO, including DataStore, DataLayer, ObjectLayer, Session, and UnitOfWork.
The DataStore is the lowest-level layer of the DevExpress ORM XPO framework. It provides a bridge between the application and the underlying data store, which could be a relational database, a NoSQL database, or any other type of data storage. The DataStore layer is responsible for establishing a connection to the data store, executing database commands, and managing transactions.
For that extremely important job it only needs one property (AutoCreateOption) and three methods:
ModifyData(ModificationStatement[])
SelectData(SelectStatement[])
UpdateSchema(Boolean, DBTable[])
The DataLayer is the layer above the DataStore layer in the XPO architecture. It is responsible for defining the schema of the database and mapping it to the persistent classes of the application. The DataLayer is designed to be highly extensible, allowing developers to define custom mappings and override default behavior as needed.
XPO includes the following data access layer implementations:
- SimpleDataLayer – does not support concurrent access from multiple threads.
- ThreadSafeDataLayer. – you can not add new classes to XPDictionary or modify XPO metadata at runtime.
Object Access Layer (added later on)
The ObjectLayer is the layer that provides a high-level view of the persistent objects in the application. It represents the persistent classes of the application and provides methods for creating, retrieving, updating, and deleting instances of these classes. The ObjectLayer is responsible for managing the object state and ensuring that changes made to the objects are persisted to the data store.
The ObjectLayer is a mediator between a Session or UnitOfWork and a data access layer. It translates object queries and storage schema updates to corresponding statements, and passes them to a data access layer for execution.
The Session is the layer that manages the state of the persistent objects and provides a mechanism for tracking changes made to the objects. The Session is responsible for coordinating transactions and ensuring that changes made to the objects are persisted to the data store in a consistent and atomic manner.
The UnitOfWork is the highest-level layer of the DevExpress ORM XPO framework. It provides a way to group multiple operations together into a single transaction. The UnitOfWork is responsible for managing the Session and coordinating multiple transactions across different threads or processes. It is designed to be highly scalable and can handle large volumes of data and high levels of concurrency.
Let’s recap.
XPO framework is built upon several layers, each serving a specific purpose in the application’s data access and storage. The DataStore layer provides a bridge between the application and the underlying data store, the DataLayer defines the schema of the database and maps it to the persistent classes of the application, the ObjectLayer provides a high-level view of the persistent objects in the application, the Session manages the state of the persistent objects and the UnitOfWork provides a way to group multiple operations together into a single transaction.
By understanding the role of each layer in the framework, we can build efficient and scalable applications with our favorite ORM.
Article Origin
This article was born from multiple conversations between Joche Ojeda and myself in my old home garage, where we spent hours discussing DevExpress ORM XPO and each layer’s purpose.
We reached out to DevExpress support several times, during which we learned even more about XPO’s inner workings.
Initially, we questioned the need for all the layers, but as we continued our discussions and worked on projects using the framework, we began to see the benefits that each one of them brings. (For example: we can even modify the query before XPO sends it to the DB. See below.)
public class MySimpleObjectLayer : SimpleObjectLayer, IObjectLayer { public MySimpleObjectLayer(IDataLayer dataLayer) : base(dataLayer) { } System.Collections.ICollection[] IObjectLayer.LoadObjects(Session session, ObjectsQuery[] queries) { return base.LoadObjects(session, PatchCriteria(queries)); } void IObjectLayer.LoadObjectsAsync(Session session, ObjectsQuery[] queries, DevExpress.Xpo.Helpers.AsyncLoadObjectsCallback callback) { base.LoadObjectsAsync(session, PatchCriteria(queries), callback); } List<object[]> IObjectLayer.SelectData(Session session, ObjectsQuery query, CriteriaOperatorCollection properties, CriteriaOperatorCollection groupProperties, CriteriaOperator groupCriteria) { return base.SelectData(session, PatchCriteria(query), properties, groupProperties, groupCriteria); } void IObjectLayer.SelectDataAsync(Session session, ObjectsQuery query, CriteriaOperatorCollection properties, CriteriaOperatorCollection groupProperties, CriteriaOperator groupCriteria, AsyncSelectDataCallback callback) { base.SelectDataAsync(session, PatchCriteria(query), properties, groupProperties, groupCriteria, callback); } private ObjectsQuery[] PatchCriteria(ObjectsQuery[] queries) { for (int i = 0; i < queries.Length; i++) { queries[i] = PatchCriteria(queries[i]); } return queries; } private ObjectsQuery PatchCriteria(ObjectsQuery query) { query.Criteria = GroupOperator.Combine(GroupOperatorType.And, query.Criteria, new BinaryOperator("CompanyID", "test")); return query; } }
All the experiences and knowledge gained from working with DevExpress ORM XPO inspired Joche to… SPOILER ALERT!!! write a book about XPO, which he has almost finished writing. The book, whose title is still classified, will be an amazing resource for developers looking to master XPO.
So, stay tuned and …
Until next time, XPO out!
#When you get the same questions 3 times you should write an article
#NotesToSelf