XPO POST 5: Layered Architecture

There is nothing than inspire me more to write a blog post that a regular Saint Petersburg day and by regular, I mean windy, cold, dark and rainy, but don’t get me wrong I love this city but when the weather is too nice as it was this past summer is hard to focus on writing.

So, let’s get started with the post number 5, today we are going to talk about the architecture of XPO.

If you are new to XPO you might find that the documentation is sometimes overwhelming especially because most of the articles blogs and tickets are written in totally different times and versions of XPO, so you might find some really old blog post where the WCF scenario is not supported and the XpoProviders are tightly coupled with the DotNet ADO Providers and some other cases where is the opposite case.

XPO is now 15 years old and its architecture has changed since the early versions, most of the time when you find documentation about XPO layer architecture you won’t be able to see all the layers at once.

After spending 1 month and Gilbert Arizona, developing software side by side with my dear friend and student Jose Javier Columbie and having endless technical conversations about XPO, I realize that it is not easy to explain how the XPO architecture works, so I decided to draw the XPO architecture in a formal document. Javier also drew the first version of this diagram on his notepad and as always half in Spanish and half in English as we tend to do as Latin Americans.

So, without further due, here I present you the XPO architecture diagram

If you want to get a copy of the diagram with clickable links, you can download it here XPO-Layer-Architecture.pdf

Now let’s start explaining from left to right.

Persistent Classes: this layer is basically defined by you as the programmer and is nothing more than the persistent classes you write to abstract business objects. Usually, this layer is your starting point as an XPO user, so I won’t go into deeper detail since if you are reading this post you already know how this layer works.

Data Access, Data Cache and Data Filtering: in this layer, the most basic object is the session also is the base class for all the other objects in this layer. A session is basically a cache of all the persistent objects that have been instantiated since you start manipulating your DataStore or the objects that you have queried in your DAL (Data Access Layer).

Most of the behaviours from the session are passed to its child classes, won’t explain the difference on the child classes in this article but for sure it will be on my list of topics for the following weeks.

Object Access Layer: this layer is the bridge between the session and the actual DataStore. So basically, it works as a translator for the CRUD operations done in an object-oriented manner to statement objects that will be processed in the data access layer level.

Data Access Layer: is the bridge between the object access layer and the data stores (classes that implements IDataStore) and its basically in charge of pass the statement objects to the data store so it can translate it to the proper SQL statements for a specific database like MS SQL Server, Postgres, Mysql, etc.

Data Store Layer: is the lowest layer of all and it’s in charge to translate the statement objects to DDL and DML SQL statements and execute them at the database level using ADO.

Also, as you can see in the diagram this layer can be transferred over the wire using WCF to extend the functionality on the communication with the database. Using WCF is really useful if you don’t want to expose the connection string on the application config or if you want to transport the communication to the database in any of WCF supported network protocols.

 

XPO POST 4: Connection Strings

When XPO was first released it supported MSSQL Server and MS Access as the main database systems, most of the examples and documentation did not specify how XPO connected to the database, at that time it looks like the connection to the database happened like magic.

There was little to none information about how to connect to a DBRMS that were not MSSQL Server or MS Access

So I decided to post a ticket to developer express asking how can I create the correct connection string for each of the supported database, and that is the origen of this ticket that I use on all my presentations lectures about XPO.

Here is a sample of each of the supported connection strings

AccessConnectionProvider: MSAccess                                                XpoProvider=MSAccess;Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\mydatabase.mdb;User Id=admin;Password=;
DataSetDataStore: XmlDataSet
XpoProvider=XmlDataSet;Data Source=C:\mydatabase.xml;Read Only=false
InMemoryDataStore: InMemoryDataStore
XpoProvider=InMemoryDataStore;Data Source=C:\mydatabase.xml;Read Only=false
MSSqlConnectionProvider: MSSqlServer
XpoProvider=MSSqlServer;Data Source=(local);User ID=username;Password=password;Initial Catalog=database;Persist Security Info=true
AdvantageConnectionProvider: Advantage
XpoProvider=Advantage;Data Source=\\myserver\myvolume\mypat\mydd.add;ServerType=local;User ID=ASSSYS;TrimTrailingSpaces=true
AsaConnectionProvider: Asa
XpoProvider=Asa;Uid=MyUsername;PWD=MyPassword;DBF=c:\mydatabase.db;Persist Security Info=true
AseConnectionPrvider: Ase
XpoProvider=Ase;Port=5000;Data Source=MyAseServer;User ID=MyUserName;Password=MyPassword;Initial Catalog=MyDatabase;Persist Security Info=true
DB2ConnectionProvider: DB2
XpoProvider=DB2;Server=MyAddress:MyPortNumber;User ID=MyUserName;Password=MyPassword;Database=MyDatabase;Persist Security Info=true
FirebirdConnectionProvider: Firebird
XpoProvider=Firebird;DataSource=localhost;User=SYSDBA;Password=masterkey;Database=MyDatabase.fdb;ServerType=0;Charset=NONE
MSSqlCEConnectionProvider: MSSqlServerCE
XpoProvider=MSSqlServerCE;Data Source=MyDatabase.sdf;Password=MyPassword
MySqlConnectionProvider: MySql
XpoProvider=MySql;Server=MyServerAddress;User ID=MyUserName;Password=MyPassword;Database=MyDatabase;Persist Security Info= true;Charset=utf8
ODPConnectionProvider: ODP
XpoProvider=ODP;Data Source=TORCL;User ID=MyUserName;Password=MyPassword
ODPManagedConnectionProvider: ODPManaged
XpoProvider=ODPManaged;Data Source=TORCL;User ID=MyUserName;Password=MyPassword
OracleConnectionProvider: Oracle
XpoProvider=Oracle;Data Source=TORCL;User ID=MyUserName;Password=MyPassword
PervasiveSqlConnectionProvider: Pervasive
XpoProvider=Pervasive;Server=MyServerAddress;UID=MyUserName;PWD=MyPassword;ServerDSN=MyDatabase
PostgreSqlConnectionProvider: Postgres
XpoProvider=Postgres;Server=127.0.0.1;User ID=MyUserName;Password=MyPassword;Database=MyDatabase;Encoding=UNICODE
SQLiteConnectionProvider: SQLite
XpoProvider=SQLite;Data Source=filename
VistaDBConnectionProvider: VistaDB
XpoProvider=VistaDB;Data Source=C:\mydatabase.vdb4
VistaDB5ConnectionProvider: VistaDB5
XpoProvider=VistaDB5;Data Source=C:\mydatabase.vdb5

By default, when you start using XPO without specifying a connection string it will connect by to MSAccess.

The XPO connection string is a special type of connection string, it is somehow the same as your regular .net connection string, but it includes the parameter “XpoProvider”, you can learn more about this on my post about the XpoProviders. The need of having the parameter XpoProvider is the connection string is because otherwise, it will be impossible to identify the database engine that you want to use with XPO as you can see on the following screenshot from DevExpress website.

There are 2 special cases that XPO can use a regular connection string

  1. When you are using an MSSQL Server as your RDBMS, you can just use a regular connection string without the need to specify an XpoProvider.
  2. When you are using MS Access with OleDb you can also use a just regular connection string

You can see a real-life example when you create an XAF application and you check the app or web config, here is a screenshot of the possible connection strings

Besides the connection string as literal strings, you can also ask the XpoProvider to generate the correct connection string for you on runtime using the static method of “GetConnectionString”. You can see an example of how to use PostgreSqlConnectionProvider to generate the correct connection string, in DevExpress official documentation here. The same goes for all of the XpoProviers, you can information about each provider in the documentation for the DevExpress.Xpo.DB namespace.

XPO POST 3: The XPO Providers

An XPO provider is a class that XPO uses to communicate natively to the RDBMS, most of these providers are subclasses of the base provider for SQL provider that lives in DevExpress.Data assembly.

Why is important to know how each provider works? here are some of the reasons:

  • You can change the default column type created for any of the .net data types when is translated to a database column type
  • You can alter the queries which the XPO provider generate so they will be more suited for your requirements, example handle the Index and tablespaces in Oracle
  • Support for more specialized connection strings for your RDBMS.
  • Support another version of a database engine that is currently not supported on XPO. One of my first task as an XPO user was to extend the XPO provider for the pervasive database to add support for an older version of the DBMS.

Each XPO providers is registered with a unique ID, this ID is used on the connection string as the value for the XpoProvider parameter. The ID allows XPO to know which provider should be used to create an IDataStore. You can see how XPO use the XpoProvider parameter in the connection string here

The methods that XPO actually use to create the data store is GetConnectionProvider and it will return an IDataStore instance. The main class that implements IDataStore is DataStoreBase that is the base class for ConnectionProviderSql and all the XPO providers.

When you add or extend an XpoProvider you need to create a new unique ID for it and register on your application startup. Here is an example of how to create and register your custom XpoProvider

XPO POST 2: The processor architecture

Now that we have installed XPO is time to talk a little bit about processor architecture. If you are using a 64 bits processor you can compile your .net application with the following architectures

  1. Any CPU
  2. x64
  3. x86

XPO depends on ADO.NET DataAdapters in order to connect to the different databases and ADO.NET depends on DbProviderFactory to load the correct DataAdapter

Now that we know about all the processor’s architectures and DataAdapters we can understand which adapter will be loaded by processor architecture, see the following table:

Processor architecture X86 OS X64 OS
Any CPU Will load the 32 bits Data Adapters Will load the 64 bits data adapter
X64 Won’t run on 32 bits OS Will load the 64 bits data adapter
X86 Will load the 32 bits Data Adapters Will load the 32 bits Data Adapters

 

This does not seem important now, but I come from a time when 64 bits what’s not common at all so sometimes when you were developing your application you end up working on 64-bits OS running a 32-bits database and connecting to the database using the 32-bits DataAdapters.

So, you were not able to compile your application using “Any CPU” because that will try to instantiate a DataAdapters on its 64 bits version.

Nowadays most of the DataAdapters are either Any CPU or the adapter has been compiled to each supported architecture.

There is a well know scenario where you try to connect to an MS Access Database using the OleDb.Net provider and you won’t be able to connect on 64 bits OS since XPO will ask the DbProviderFactory to instantiate an OleDb Data Adapter for 64 bits architecture and that actually does not exist.

In conclusion, knowing how ADO.NET uses the DbProviderFactory will help you to understand which DataAdapter will XPO try to load in your application.

XPO POST 1: How to obtain the XPO library

Well, let’s start at the beginning. How do I gain access to use XPO, well there are several install XPO on your next DotNet project, here is a list of them.

  1. If you own any of DevExpress license you already have access to XPO you can see the available licenses here
  2. Download the NuGet package: XPO just recently became free to use class library, that’s right, you get to use the most powerful ORM on the DotNet world for free, no questions asked, you can read more about that here. Now to obtain the NuGet package you can use any of the following approaches:

a) Use the console command: Install-Package DevExpress.Xpo -Version 18.1.6

b) Search for the NuGet package using the following package id “DevExpress.Xpo”

Any XPO project should contain references to at least 2 libraries

  • DevExpress.Xpo.vXX.X.X in this library you will find all the base objects and attributes necessary to create  persistent objects
  • DevExpress.Data.vXX.X.X, in this assembly you will find all the necessary objects to query the database using criteria operators and you will also find the ConnectionProviderSql used as a base class for all XPO Providers

After installing the NuGet package or adding the assembly references you are ready to start creating your O.R.M classes