When dealing with services or websites where many operations can be requested asynchronously from different threads, you must ensure that you use the ThreadSafeDataLayer.
The DX help document http://documentation.devexpress.com/#XPO/clsDevExpressXpoThreadSafeDataLayertopic does have a little Note which reads:
Prior to performing any operations with persistent objects in a data store using thread-safe data access layers, call the Session.CreateObjectTypeRecords method to obtain complete metadata information on the persistent objects.
Now the problem is, some XPO novices may run into issues, as per “XPO Best Practices” the Default Session should be null and therefore, this will mean that they will create a new Session using their newly created ThreadSafeDataLayer. The issue is here is that the ThreadSafeDataLayer requires all SchemaUpdates/ObjectType records to already be in place (due to the asynchronous ways the ThreadSafeDataLayer cannot safely ensure that if it did a UpdateSchema/CreateObjectTypeRecords that there isn’t already another thread requesting this)
So, what does this note from DX mean?
Basically you need to use a SimpleDataLayer first to ensure your database schema is valid and up to date. When I create a new DataStore during my service/application initialisation I have a pattern like this:
' Define assemblies that contain XPO objects used in this data store
Dim DataAssemblies As New List(Of Reflection.Assembly)
DataAssemblies.Add(GetType(Central.BaseObject).Assembly)
DataAssemblies.Add(GetType(Data.Objects.BaseObject).Assembly)
' Define the datastore
Dim ds As IDataStore = New InMemoryDataStore() ' using memory store just for an example
' other real examples to create a datastore, this can be anything such as Access, MySQL, SQLite, MSSQLCE etc.
'ds = XpoDefault.GetConnectionProvider(MSSqlConnectionProvider.GetConnectionString("localhost", "myUsername", "myPassword", "testdb"), AutoCreateOption.DatabaseAndSchema, Nothing)
'ds = MSSqlConnectionProvider.CreateProviderFromString("Data Source=localhost;Initial Catalog=testdb;User Id=myUsername;Password=myPassword;", AutoCreateOption.DatabaseAndSchema, Nothing)
' Ensure data schema is updated
Using sdl As New SimpleDataLayer(ds)
Using uow As New UnitOfWork(sdl)
uow.CreateObjectTypeRecords(DataAssemblies.ToArray)
uow.UpdateSchema(DataAssemblies.ToArray)
End Using
End Using
'Create dictionary to tell ThreadSafeDataLayer what Classes will be persisted
Dim AssDict As New Metadata.ReflectionDictionary()
AssDict.CollectClassInfos(DataAssemblies.ToArray) ' Will iterate the assembly to find all IXPObject implementors
Dim tsdl As New ThreadSafeDataLayer(AssDict, ds)
'Now it is safe to use the ThreadSafeDataLayer
Using uow As New UnitOfWork(tsdl)
' Do Something
End Using
// Define assemblies that contain XPO objects used in this data store
List DataAssemblies = new List();
DataAssemblies.Add(typeof(Central.BaseObject).Assembly);
DataAssemblies.Add(typeof(Data.Objects.BaseObject).Assembly);
// Define the datastore
IDataStore ds = new InMemoryDataStore();
// using memory store just for an example
// other real examples to create a datastore, this can be anything such as Access, MySQL, SQLite, MSSQLCE etc.
//ds = XpoDefault.GetConnectionProvider(MSSqlConnectionProvider.GetConnectionString("localhost", "myUsername", "myPassword", "testdb"), AutoCreateOption.DatabaseAndSchema, Nothing)
//ds = MSSqlConnectionProvider.CreateProviderFromString("Data Source=localhost;Initial Catalog=testdb;User Id=myUsername;Password=myPassword;", AutoCreateOption.DatabaseAndSchema, Nothing)
// Ensure data schema is updated
using (SimpleDataLayer sdl = new SimpleDataLayer(ds)) {
using (UnitOfWork uow = new UnitOfWork(sdl)) {
uow.CreateObjectTypeRecords(DataAssemblies.ToArray());
uow.UpdateSchema(DataAssemblies.ToArray());
}
}
//Create dictionary to tell ThreadSafeDataLayer what Classes will be persisted
Metadata.ReflectionDictionary AssDict = new Metadata.ReflectionDictionary();
AssDict.CollectClassInfos(DataAssemblies.ToArray());
// Will iterate the assembly to find all IXPObject implementors
ThreadSafeDataLayer tsdl = new ThreadSafeDataLayer(AssDict, ds);
//Now it is safe to use the ThreadSafeDataLayer
using (UnitOfWork uow = new UnitOfWork(tsdl)) {
// Do Something
}
This seems to be the safest way to ensure that during your service/application running that you won’t end up with SchemaUpdateRequired exceptions or other weird exceptions with Index’s etc.
Hope this helps
Add comment