context: // --------------------------------------------------------------------------------------------------------------------
  // <copyright file="Session.cs" company="Allors bvba">
  //   Copyright 2002-2017 Allors bvba.
  // 
  // Dual Licensed under
  //   a) the Lesser General Public Licence v3 (LGPL)
  //   b) the Allors License
  // 
  // The LGPL License is included in the file lgpl.txt.
  // The Allors License is an addendum to your contract.
  // 
  // Allors Platform is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  // GNU General Public License for more details.
  // 
  // For more information visit http://www.allors.com/legal
  // </copyright>
  // --------------------------------------------------------------------------------------------------------------------
  
  namespace Allors.Adapters.Memory
  {
      using System;
      using System.Collections.Generic;
      using System.Xml;
  
      using Allors.Meta;
  
      using Microsoft.Extensions.DependencyInjection;
  
      public class Session : ISession
      {
          private static readonly HashSet<Strategy> EmptyStrategies = new HashSet<Strategy>();
          private static readonly IObject[] EmptyObjects = { };
  
          private readonly Dictionary<IObjectType, IObjectType[]> concreteClassesByObjectType;
  
          private readonly Database database;
  
          private ChangeSet changeSet;
  
          private bool busyCommittingOrRollingBack;
  
          private Dictionary<long, Strategy> strategyByObjectId;
          private Dictionary<IObjectType, HashSet<Strategy>> strategiesByObjectType;
  
          private long currentId;
  
          internal Session(Database database)
          {
              var serviceScopeFactory = database.ServiceProvider.GetRequiredService<IServiceScopeFactory>();
              var scope = serviceScopeFactory.CreateScope();
              this.ServiceProvider = scope.ServiceProvider;
  
              this.database = database;
              this.busyCommittingOrRollingBack = false;
  
              this.concreteClassesByObjectType = new Dictionary<IObjectType, IObjectType[]>();
  
              this.changeSet = new ChangeSet();
  
              this.Reset();
          }
  
          public IServiceProvider ServiceProvider { get; }
  
          public IDatabase Population => this.database;
  
          public IDatabase Database => this.database;
  
          public bool IsProfilingEnabled => false;
  
          internal ChangeSet MemoryChangeSet => this.changeSet;
  
          internal Database MemoryDatabase => this.database;
  
          public void Commit()
          {
              if (!this.busyCommittingOrRollingBack)
              {
                  try
                  {
                      this.busyCommittingOrRollingBack = true;
  
                      IList<Strategy> strategiesToDelete = null;
                      foreach (var dictionaryEntry in this.strategyByObjectId)
                      {
                          var strategy = dictionaryEntry.Value;
  
                          strategy.Commit();
  
                          if (strategy.IsDeleted)
                          {
                              if (strategiesToDelete == null)
                              {
                                  strategiesToDelete = new List<Strategy>();
                              }
  
                              strategiesToDelete.Add(strategy);
                          }
                      }
  
                      if (strategiesToDelete != null)
                      {
                          foreach (var strategy in strategiesToDelete)
                          {
                              this.strategyByObjectId.Remove(strategy.ObjectId);
  
                              HashSet<Strategy> strategies;
                              if (this.strategiesByObjectType.TryGetValue(strategy.UncheckedObjectType, out strategies))
                              {
                                  strategies.Remove(strategy);
                              }
                          }
                      }
  
                      this.changeSet = new ChangeSet();
                  }
                  finally
                  {
                      this.busyCommittingOrRollingBack = false;
                  }
              }
          }
  
          public void Rollback()
          {
              if (!this.busyCommittingOrRollingBack)
              {
                  try
                  {
                      this.busyCommittingOrRollingBack = true;
  
                      foreach (var strategy in new List<Strategy>(this.strategyByObjectId.Values))
                      {
                          strategy.Rollback();
                          if (strategy.IsDeleted)
                          {
                              this.strategyByObjectId.Remove(strategy.ObjectId);
  
                              HashSet<Strategy> strategies;
                              if (this.strategiesByObjectType.TryGetValue(strategy.UncheckedObjectType, out strategies))
                              {
                                  strategies.Remove(strategy);
                              }
                          }
                      }
  
                      this.changeSet = new ChangeSet();
                  }
                  finally
                  {
                      this.busyCommittingOrRollingBack = false;
                  }
              }
          }
  
          public void Dispose()
          {
              this.Rollback();
          }
  
          public T Create<T>() where T : IObject
          {
              var objectType = this.database.ObjectFactory.GetObjectTypeForType(typeof(T));
  
              var @class = objectType as IClass;
              if (@class == null)
              {
                  throw new Exception("IObjectType should be a class");
              }
              
              return (T)this.Create(@class);
          }
  
          public IObject[] Create(IClass objectType, int count)
          {
              var arrayType = this.database.ObjectFactory.GetTypeForObjectType(objectType);
              var allorsObjects = (IObject[])Array.CreateInstance(arrayType, count);
              for (var i = 0; i < count; i++)
              {
                  allorsObjects[i] = this.Create(objectType);
              }
  
              return allorsObjects;
          }
  
          public IObject Insert(IClass @class, string objectId)
          {
              var id = long.Parse(objectId);
              return this.Insert(@class, id);
          }
  
          public IObject Insert(IClass @class, long objectId)
          {
              var strategy = this.InsertStrategy(@class, objectId, Memory.Database.IntialVersion);
              return strategy.GetObject();
          }
  
          public IObject Instantiate(string objectIdString)
          {
  
gt:             if (objectIdString == null)