context: // --------------------------------------------------------------------------------------------------------------------
  // <copyright file="Strategy.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>
  // <summary>
  //   Defines the AllorsStrategySql type.
  // </summary>
  // --------------------------------------------------------------------------------------------------------------------
  
  namespace Allors.Adapters.Object.SqlClient
  {
      using System;
      using System.Collections.Generic;
      using System.Linq;
  
      using Adapters;
  
      using Meta;
  
      public class Strategy : IStrategy
      {
          private readonly Reference reference;
  
          private IObject allorsObject;
          private Roles roles;
  
          internal Strategy(Reference reference)
          {
              this.reference = reference;
              this.ObjectId = reference.ObjectId;
          }
  
          ISession IStrategy.Session => this.reference.Session;
  
          public Session Session => this.reference.Session;
  
          public IClass Class
          {
              get
              {
                  if (!this.reference.Exists)
                  {
                      throw new Exception("Object that had  " + this.reference.Class.Name + " with id " + this.ObjectId + " does not exist");
                  }
  
                  return this.reference.Class;
              }
          }
  
          public long ObjectId { get; }
  
          public long ObjectVersion => this.reference.Version;
  
          public bool IsDeleted => !this.reference.Exists;
  
          public bool IsNewInSession => this.reference.IsNew;
  
          internal Roles Roles => this.roles ?? (this.roles = this.reference.Session.State.GetOrCreateRoles(this.reference));
  
          internal Reference Reference => this.reference;
  
          public IObject GetObject()
          {
              return this.allorsObject ?? (this.allorsObject = this.reference.Session.Database.ObjectFactory.Create(this));
          }
  
          public virtual void Delete()
          {
              this.AssertExist();
  
              foreach (var roleType in this.Class.RoleTypes)
              {
                  if (roleType.ObjectType.IsComposite)
                  {
                      this.RemoveRole(roleType.RelationType);
                  }
              }
  
              foreach (var associationType in this.Class.AssociationTypes)
              {
                  var relationType = associationType.RelationType;
                  var roleType = relationType.RoleType;
  
                  if (associationType.IsMany)
                  {
                      foreach (var association in this.Session.GetAssociations(this, associationType))
                      {
                          var associationStrategy = this.Session.State.GetOrCreateReferenceForExistingObject(association, this.Session).Strategy;
                          if (roleType.IsMany)
                          {
                              associationStrategy.RemoveCompositeRole(relationType, this.GetObject()); 
                          }
                          else
                          {
                              associationStrategy.RemoveCompositeRole(relationType);
                          }
                      }
                  }
                  else
                  {
                      var association = this.GetCompositeAssociation(relationType);
                      if (association != null)
                      {
                          if (roleType.IsMany)
                          {
                              association.Strategy.RemoveCompositeRole(roleType.RelationType, this.GetObject());
                          }
                          else
                          {
                              association.Strategy.RemoveCompositeRole(roleType.RelationType);
                          }
                      }
                  }
              }
  
              this.Session.Commands.DeleteObject(this);
              this.reference.Exists = false;
  
              this.Session.State.ChangeSet.OnDeleted(this.ObjectId);
          }
  
          public virtual bool ExistRole(IRelationType relationType)
          {
              if (relationType.RoleType.ObjectType.IsUnit)
              {
                  return this.ExistUnitRole(relationType);
              }
  
              return relationType.RoleType.IsMany 
                  ? this.ExistCompositeRoles(relationType) 
                  : this.ExistCompositeRole(relationType);
          }
  
          public virtual object GetRole(IRelationType relationType)
          {
              if (relationType.RoleType.ObjectType.IsUnit)
              {
                  return this.GetUnitRole(relationType);
              }
  
              return relationType.RoleType.IsMany
                         ? (object)this.GetCompositeRoles(relationType)
                         : this.GetCompositeRole(relationType);
          }
  
          public virtual void SetRole(IRelationType relationType, object value)
          {
              if (relationType.RoleType.ObjectType.IsUnit)
              {
                  this.SetUnitRole(relationType, value);
              }
              else
              {
                  if (relationType.RoleType.IsMany)
                  {
                      var roleExtent = value as Allors.Extent ?? ((ICollection<IObject>)value).ToArray();
                      this.SetCompositeRoles(relationType, roleExtent);
                  }
                  else
                  {
                      this.SetCompositeRole(relationType, (IObject)value);
                  }
              }
          }
  
          public virtual void RemoveRole(IRelationType relationType)
          {
              if (relationType.RoleType.ObjectType.IsUnit)
              {
                  this.RemoveUnitRole(relationType);
              }
              else
              {
                  if (relationType.RoleType.IsMany)
                  {
                      this.RemoveCompositeRoles(relationType);
                  }
                  else
                  {
                      this.RemoveCompositeRole(relationType);
                  }
              }
          }
  
          public virtual bool ExistUnitRole(IRelationType relationType)
          {
              return this.GetUnitRole(relationType) != null;
          }
  
          public virtual object GetUnitRole(IRelationType relationType)
          {
              this.AssertExist();
  
              var roleType = relationType.RoleType;
              return this.Roles.GetUnitRole(roleType);
          }
  
          public virtual void SetUnitRole(IRelationType relationType, object role)
          {
              this.AssertExist();
  
              RoleAssertions.UnitRoleChecks(this, relationType.RoleType);
  
              if (role != null)
              {
                  role = relationType.RoleType.Normalize(role);
              }
  
              var oldUnit = this.GetUnitRole(relationType);
              if (!Equals(oldUnit, role))
              {
                  this.Roles.SetUnitRole(relationType.RoleType, role);
              }
          }
  
          public virtual void RemoveUnitRole(IRelationType relationType)
          {
              this.SetUnitRole(relationType, null);
          }
  
          public virtual bool ExistCompositeRole(IRelationType relationType)
          {
              return this.GetCompositeRole(relationType) != null;
          }
  
          public virtual IObject GetCompositeRole(IRelationType relationType)
          {
              this.AssertExist();
  
  
gt:             var role = this.Roles.GetCompositeRole(relationType.RoleType);