The Enterprise Core Objects Persistence Mapper is a singleton which is used by all EcoSpace instances. It’s purpose is to load mapping information from the DB when your app starts and to cache it, improving performance.
I needed a connection per client, all running within a single application. This was a problem because once the PMP is created its connection string is tied to a single database. So I had to come up with a new PersistenceMapperDynamicSharer component. It is used on the EcoSpace to specify the PMapper type; additionally you can specify a connection string to use.
It works by dynamically creating a descendant class of your PersistenceMapperProvider at runtime, one for each connection string.
1: public class PersistenceMapperDynamicSharer : PersistenceMapperSharer
2: {
3: static ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
4: static Dictionary<string, PersistenceMapperProvider> MapperProviders = new Dictionary<string, PersistenceMapperProvider>();
5:
6: [Browsable(false)]
7: public string ConnectionString { get; set; }
8:
9: public override IPersistenceMapper GetPersistenceMapper(ITypeSystemService typeSystemService)
10: {
11: return GetPersistenceMapperProvider().GetPersistenceMapper(typeSystemService);
12: }
13:
14: public override void ReturnPersistenceMapper(IPersistenceMapper persistenceMapper)
15: {
16: GetPersistenceMapperProvider().ReturnPersistenceMapper(persistenceMapper);
17: }
18:
19: PersistenceMapperProvider GetPersistenceMapperProvider()
20: {
21: //No connection string = default mapper provider
22: if (string.IsNullOrEmpty(ConnectionString))
23: return PersistenceMapperProvider.GetInstance(MapperProviderType);
24:
25: PersistenceMapperProvider result;
26: Locker.EnterUpgradeableReadLock();
27: try
28: {
29: if (MapperProviders.TryGetValue(ConnectionString, out result))
30: return result;
31: Locker.EnterWriteLock();
32: try
33: {
34: var mapperType = CreateNewPersistenceMapperProviderType();
35: result = (PersistenceMapperProvider)Activator.CreateInstance(mapperType);
36: ((IDynamicallySharedPersistenceMapper)result).SetConnectionString(ConnectionString);
37: MapperProviders[ConnectionString] = result;
38: }
39: finally
40: {
41: Locker.ExitWriteLock();
42: }
43: }
44: finally
45: {
46: Locker.ExitUpgradeableReadLock();
47: }
48: return result;
49: }
50:
51: Type CreateNewPersistenceMapperProviderType()
52: {
53: string guid = Guid.NewGuid().ToString();
54: var assemblyName = new AssemblyName(guid);
55: var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
56: assemblyName,
57: System.Reflection.Emit.AssemblyBuilderAccess.Run);
58: var moduleBuilder = assemblyBuilder.DefineDynamicModule(guid);
59: var typeBuilder = moduleBuilder.DefineType(
60: guid,
61: TypeAttributes.Class | TypeAttributes.Public,
62: MapperProviderType);
63: return typeBuilder.CreateType();
64: }
65: }
On my EcoSpace I have a method called ActivateWithConnectionString which I can use whenever I need to activate the EcoSpace connecting to a connection string OTHER than the default…
1: public void ActivateWithConnectionString(string connectionString)
2: {
3: persistenceMapperDynamicSharer1.ConnectionString = connectionString;
4: Active = true;
5: }
And on my PersistenceMapperProvider I need to implement IDynamicallySharedPersistenceMapper like so…
1: void IDynamicallySharedPersistenceMapper.SetConnectionString(string connectionString)
2: {
3: sqlConnection1.ConnectionString = connectionString;
4: }
Now I can benefit from the performance gains from the singleton-pattern implemented by PersistenceMapperProvider and connect to different databases.