protected ShardedSessionFactoryImpl(
            ShardedSessionFactoryImpl parent,
            IEnumerable <ShardId> shardIds,
            IShardStrategyFactory shardStrategyFactory)
        {
            this.shardIdsBySessionFactory                    = new Dictionary <ISessionFactoryImplementor, ICollection <ShardId> >();
            this.classesWithoutTopLevelSaveSupport           = parent.classesWithoutTopLevelSaveSupport;
            this.checkAllAssociatedObjectsForDifferentShards = parent.checkAllAssociatedObjectsForDifferentShards;
            this.controlSessionFactory = parent.controlSessionFactory;

            var uniqueShardIds = new HashSet <ShardId>(shardIds);

            foreach (var pair in parent.shardIdsBySessionFactory)
            {
                var shardIdsSubset = new HashSet <ShardId>(pair.Value);
                shardIdsSubset.IntersectWith(uniqueShardIds);
                if (shardIdsSubset.Count > 0)
                {
                    this.shardIdsBySessionFactory.Add(pair.Key, shardIdsSubset);
                }
            }

            shardStrategy = shardStrategyFactory.NewShardStrategy(
                shardIdsBySessionFactory.SelectMany(c => c.Value));
        }
        /// <summary>
        /// Constructs a ShardedSessionFactoryImpl
        /// </summary>
        /// <param name="shardIdsBySessionFactory">Mapping of SessionFactories to shard ids.
        ///  When using virtual shards, this map associates SessionFactories (physical
        ///  shards) with virtual shards (shard ids).  Map cannot be empty.
        ///  Map keys cannot be null.  Map values cannot be null or empty.</param>
        /// <param name="shardStrategyFactory">factory that knows how to create the <see cref="IShardStrategy"/>
        ///  that will be used for all shard-related operations</param>
        /// <param name="classesWithoutTopLevelSaveSupport"> All classes that cannot be saved
        ///  as top-level objects</param>
        /// <param name="checkAllAssociatedObjectsForDifferentShards">Flag that controls
        ///  whether or not we do full cross-shard relationshp checking (very slow)</param>
        public ShardedSessionFactoryImpl(
            IDictionary <ISessionFactoryImplementor, ICollection <ShardId> > shardIdsBySessionFactory,
            IShardStrategyFactory shardStrategyFactory,
            IEnumerable <System.Type> classesWithoutTopLevelSaveSupport,
            bool checkAllAssociatedObjectsForDifferentShards)
        {
            Preconditions.CheckNotNull(shardIdsBySessionFactory);
            Preconditions.CheckNotNull(shardStrategyFactory);
            Preconditions.CheckNotNull(classesWithoutTopLevelSaveSupport);

            this.shardIdsBySessionFactory                    = new Dictionary <ISessionFactoryImplementor, ICollection <ShardId> >(shardIdsBySessionFactory);
            this.classesWithoutTopLevelSaveSupport           = new HashSet <System.Type>(classesWithoutTopLevelSaveSupport);
            this.checkAllAssociatedObjectsForDifferentShards = checkAllAssociatedObjectsForDifferentShards;

            var uniqueShardIds = new HashSet <ShardId>();

            foreach (var entry in shardIdsBySessionFactory)
            {
                ISessionFactoryImplementor implementor = entry.Key;
                Preconditions.CheckNotNull(implementor);

                var shardIdSet = entry.Value;
                Preconditions.CheckNotNull(shardIdSet);
                Preconditions.CheckState(!(shardIdSet.Count == 0));

                foreach (ShardId shardId in shardIdSet)
                {
                    //TODO: we should change it so we specify control shard in configuration
                    if (shardId.Id == CONTROL_SHARD_ID)
                    {
                        this.controlSessionFactory = implementor;
                    }
                    if (!uniqueShardIds.Add(shardId))
                    {
                        string msg = string.Format("Cannot have more than one shard with shard id {0}.", shardId.Id);
                        Log.Error(msg);
                        throw new HibernateException(msg);
                    }

                    if (!this.shardIdsBySessionFactory.ContainsKey(implementor))
                    {
                        this.shardIdsBySessionFactory.Add(implementor, new HashSet <ShardId>());
                    }
                    this.shardIdsBySessionFactory[implementor].Add(shardId);
                }
            }

            if (this.controlSessionFactory == null)
            {
                string message = string.Format(
                    CultureInfo.InvariantCulture,
                    "Cannot find control shard. Please ensure that one control shard exists with shard id '{0}'. " +
                    "A control shard is required for operations that cannot be distributed across shards, such as the " +
                    "generation of unique sequence numbers within the shard.",
                    CONTROL_SHARD_ID);
                Log.Error(message);
                throw new ArgumentException(message, "shardIdsBySessionFactory");
            }

            // now that we have all our shard ids, construct our shard strategy
            shardStrategy = shardStrategyFactory.NewShardStrategy(
                shardIdsBySessionFactory.SelectMany(c => c.Value));
            SetupIdGenerators();
        }
        /// <summary>
        /// Constructs a ShardedSessionFactoryImpl
        /// </summary>
        /// <param name="shardIds"> The ids of the shards with which this SessionFactory should be associated.</param>
        /// <param name="sessionFactoryShardIdMap">Mapping of SessionFactories to shard ids.
        ///  When using virtual shards, this map associates SessionFactories (physical
        ///  shards) with virtual shards (shard ids).  Map cannot be empty.
        ///  Map keys cannot be null.  Map values cannot be null or empty.</param>
        /// <param name="shardStrategyFactory">factory that knows how to create the <see cref="IShardStrategy"/>
        ///  that will be used for all shard-related operations</param>
        /// <param name="classesWithoutTopLevelSaveSupport"> All classes that cannot be saved
        ///  as top-level objects</param>
        /// <param name="checkAllAssociatedObjectsForDifferentShards">Flag that controls
        ///  whether or not we do full cross-shard relationshp checking (very slow)</param>
        public ShardedSessionFactoryImpl(
            ICollection <ShardId> shardIds,
            IDictionary <ISessionFactoryImplementor, Set <ShardId> > sessionFactoryShardIdMap,
            IShardStrategyFactory shardStrategyFactory,
            ISet <System.Type> classesWithoutTopLevelSaveSupport,
            bool checkAllAssociatedObjectsForDifferentShards)
        {
            Preconditions.CheckNotNull(sessionFactoryShardIdMap);
            Preconditions.CheckArgument(!(sessionFactoryShardIdMap.Count == 0));
            Preconditions.CheckNotNull(shardStrategyFactory);
            Preconditions.CheckNotNull(classesWithoutTopLevelSaveSupport);

            sessionFactories = new List <ISessionFactoryImplementor>(sessionFactoryShardIdMap.Keys);
            this.sessionFactoryShardIdMap                    = new Dictionary <ISessionFactoryImplementor, Set <ShardId> >();
            fullSessionFactoryShardIdMap                     = sessionFactoryShardIdMap;
            this.classesWithoutTopLevelSaveSupport           = new HashedSet <System.Type>(classesWithoutTopLevelSaveSupport);
            this.checkAllAssociatedObjectsForDifferentShards = checkAllAssociatedObjectsForDifferentShards;
            Set <ShardId> uniqueShardIds = new HashedSet <ShardId>();
            ISessionFactoryImplementor controlSessionFactoryToSet = null;

            foreach (var entry in sessionFactoryShardIdMap)
            {
                ISessionFactoryImplementor implementor = entry.Key;
                Preconditions.CheckNotNull(implementor);
                Set <ShardId> shardIdSet = entry.Value;
                Preconditions.CheckNotNull(shardIdSet);
                Preconditions.CheckState(!(shardIdSet.Count == 0));

                foreach (ShardId shardId in shardIdSet)
                {
                    //TODO: we should change it so we specify control shard in configuration
                    if (shardId.Id == CONTROL_SHARD_ID)
                    {
                        controlSessionFactoryToSet = implementor;
                    }
                    if (!uniqueShardIds.Add(shardId))
                    {
                        string msg = string.Format("Cannot have more than one shard with shard id {0}.", shardId.Id);
                        log.Error(msg);
                        throw new HibernateException(msg);
                    }
                    if (shardIds.Contains(shardId))
                    {
                        if (!this.sessionFactoryShardIdMap.ContainsKey(implementor))
                        {
                            this.sessionFactoryShardIdMap.Add(implementor, new HashedSet <ShardId>());
                        }

                        this.sessionFactoryShardIdMap[implementor].Add(shardId);
                    }
                }
            }
            // make sure someone didn't associate a session factory with a shard id
            // that isn't in the full list of shards
            foreach (ShardId shardId in shardIds)
            {
                Preconditions.CheckState(uniqueShardIds.Contains(shardId));
            }
            controlSessionFactory = controlSessionFactoryToSet;
            // now that we have all our shard ids, construct our shard strategy
            shardStrategy = shardStrategyFactory.NewShardStrategy(shardIds);
            SetupIdGenerators();
        }
        /// <summary>
        /// Constructs a ShardedSessionFactoryImpl
        /// </summary>
        /// <param name="shardIdsBySessionFactory">Mapping of SessionFactories to shard ids. 
        ///  When using virtual shards, this map associates SessionFactories (physical
        ///  shards) with virtual shards (shard ids).  Map cannot be empty.
        ///  Map keys cannot be null.  Map values cannot be null or empty.</param>
        /// <param name="shardStrategyFactory">factory that knows how to create the <see cref="IShardStrategy"/> 
        ///  that will be used for all shard-related operations</param>
        /// <param name="classesWithoutTopLevelSaveSupport"> All classes that cannot be saved
        ///  as top-level objects</param>
        /// <param name="checkAllAssociatedObjectsForDifferentShards">Flag that controls
        ///  whether or not we do full cross-shard relationshp checking (very slow)</param>
        public ShardedSessionFactoryImpl(
            IDictionary<ISessionFactoryImplementor, ICollection<ShardId>> shardIdsBySessionFactory,
            IShardStrategyFactory shardStrategyFactory,
            IEnumerable<System.Type> classesWithoutTopLevelSaveSupport,
            bool checkAllAssociatedObjectsForDifferentShards)
        {
            Preconditions.CheckNotNull(shardIdsBySessionFactory);
            Preconditions.CheckNotNull(shardStrategyFactory);
            Preconditions.CheckNotNull(classesWithoutTopLevelSaveSupport);

            this.shardIdsBySessionFactory = new Dictionary<ISessionFactoryImplementor, ICollection<ShardId>>(shardIdsBySessionFactory);
            this.classesWithoutTopLevelSaveSupport = new HashSet<System.Type>(classesWithoutTopLevelSaveSupport);
            this.checkAllAssociatedObjectsForDifferentShards = checkAllAssociatedObjectsForDifferentShards;

            var uniqueShardIds = new HashSet<ShardId>();
            foreach (var entry in shardIdsBySessionFactory)
            {
                ISessionFactoryImplementor implementor = entry.Key;
                Preconditions.CheckNotNull(implementor);

                var shardIdSet = entry.Value;
                Preconditions.CheckNotNull(shardIdSet);
                Preconditions.CheckState(!(shardIdSet.Count == 0));

                foreach (ShardId shardId in shardIdSet)
                {
                    //TODO: we should change it so we specify control shard in configuration
                    if (shardId.Id == CONTROL_SHARD_ID)
                    {
                        this.controlSessionFactory = implementor;
                    }
                    if (!uniqueShardIds.Add(shardId))
                    {
                        string msg = string.Format("Cannot have more than one shard with shard id {0}.", shardId.Id);
                        Log.Error(msg);
                        throw new HibernateException(msg);
                    }

                    if (!this.shardIdsBySessionFactory.ContainsKey(implementor))
                    {
                        this.shardIdsBySessionFactory.Add(implementor, new HashSet<ShardId>());
                    }
                    this.shardIdsBySessionFactory[implementor].Add(shardId);
                }
            }

            if (this.controlSessionFactory == null)
            {
                string message = string.Format(
                    CultureInfo.InvariantCulture,
                    "Cannot find control shard. Please ensure that one control shard exists with shard id '{0}'. " +
                    "A control shard is required for operations that cannot be distributed across shards, such as the " +
                    "generation of unique sequence numbers within the shard.",
                    CONTROL_SHARD_ID);
                Log.Error(message);
                throw new ArgumentException(message, "shardIdsBySessionFactory");
            }

            // now that we have all our shard ids, construct our shard strategy
            shardStrategy = shardStrategyFactory.NewShardStrategy(
                shardIdsBySessionFactory.SelectMany(c => c.Value));
            SetupIdGenerators();
        }
        protected ShardedSessionFactoryImpl(
            ShardedSessionFactoryImpl parent,
            IEnumerable<ShardId> shardIds,
            IShardStrategyFactory shardStrategyFactory)
        {
            this.shardIdsBySessionFactory = new Dictionary<ISessionFactoryImplementor, ICollection<ShardId>>();
            this.classesWithoutTopLevelSaveSupport = parent.classesWithoutTopLevelSaveSupport;
            this.checkAllAssociatedObjectsForDifferentShards = parent.checkAllAssociatedObjectsForDifferentShards;
            this.controlSessionFactory = parent.controlSessionFactory;

            var uniqueShardIds = new HashSet<ShardId>(shardIds);
            foreach (var pair in parent.shardIdsBySessionFactory)
            {
                var shardIdsSubset = new HashSet<ShardId>(pair.Value);
                shardIdsSubset.IntersectWith(uniqueShardIds);
                if (shardIdsSubset.Count > 0)
                {
                    this.shardIdsBySessionFactory.Add(pair.Key, shardIdsSubset);
                }
            }

            shardStrategy = shardStrategyFactory.NewShardStrategy(
                shardIdsBySessionFactory.SelectMany(c => c.Value));
        }
        /// <summary>
        /// Constructs a ShardedSessionFactoryImpl
        /// </summary>
        /// <param name="shardIds"> The ids of the shards with which this SessionFactory should be associated.</param>
        /// <param name="sessionFactoryShardIdMap">Mapping of SessionFactories to shard ids. 
        ///  When using virtual shards, this map associates SessionFactories (physical
        ///  shards) with virtual shards (shard ids).  Map cannot be empty.
        ///  Map keys cannot be null.  Map values cannot be null or empty.</param>
        /// <param name="shardStrategyFactory">factory that knows how to create the <see cref="IShardStrategy"/> 
        ///  that will be used for all shard-related operations</param>
        /// <param name="classesWithoutTopLevelSaveSupport"> All classes that cannot be saved
        ///  as top-level objects</param>
        /// <param name="checkAllAssociatedObjectsForDifferentShards">Flag that controls
        ///  whether or not we do full cross-shard relationshp checking (very slow)</param>
        public ShardedSessionFactoryImpl(
			ICollection<ShardId> shardIds,
			IDictionary<ISessionFactoryImplementor, Set<ShardId>> sessionFactoryShardIdMap,
			IShardStrategyFactory shardStrategyFactory,
			ISet<System.Type> classesWithoutTopLevelSaveSupport,
			bool checkAllAssociatedObjectsForDifferentShards)
        {
            Preconditions.CheckNotNull(sessionFactoryShardIdMap);
            Preconditions.CheckArgument(!(sessionFactoryShardIdMap.Count == 0));
            Preconditions.CheckNotNull(shardStrategyFactory);
            Preconditions.CheckNotNull(classesWithoutTopLevelSaveSupport);

            sessionFactories = new List<ISessionFactoryImplementor>(sessionFactoryShardIdMap.Keys);
            this.sessionFactoryShardIdMap = new Dictionary<ISessionFactoryImplementor, Set<ShardId>>();
            fullSessionFactoryShardIdMap = sessionFactoryShardIdMap;
            this.classesWithoutTopLevelSaveSupport = new HashedSet<System.Type>(classesWithoutTopLevelSaveSupport);
            this.checkAllAssociatedObjectsForDifferentShards = checkAllAssociatedObjectsForDifferentShards;
            Set<ShardId> uniqueShardIds = new HashedSet<ShardId>();
            ISessionFactoryImplementor controlSessionFactoryToSet = null;

            foreach (var entry in sessionFactoryShardIdMap)
            {
                ISessionFactoryImplementor implementor = entry.Key;
                Preconditions.CheckNotNull(implementor);
                Set<ShardId> shardIdSet = entry.Value;
                Preconditions.CheckNotNull(shardIdSet);
                Preconditions.CheckState(!(shardIdSet.Count == 0));

                foreach (ShardId shardId in shardIdSet)
                {
                    //TODO: we should change it so we specify control shard in configuration
                    if (shardId.Id == CONTROL_SHARD_ID)
                    {
                        controlSessionFactoryToSet = implementor;
                    }
                    if (!uniqueShardIds.Add(shardId))
                    {
                        string msg = string.Format("Cannot have more than one shard with shard id {0}.", shardId.Id);
                        log.Error(msg);
                        throw new HibernateException(msg);
                    }
                    if (shardIds.Contains(shardId))
                    {
                        if (!this.sessionFactoryShardIdMap.ContainsKey(implementor))
                            this.sessionFactoryShardIdMap.Add(implementor, new HashedSet<ShardId>());

                        this.sessionFactoryShardIdMap[implementor].Add(shardId);
                    }
                }
            }
            // make sure someone didn't associate a session factory with a shard id
            // that isn't in the full list of shards
            foreach (ShardId shardId in shardIds)
            {
                Preconditions.CheckState(uniqueShardIds.Contains(shardId));
            }
            controlSessionFactory = controlSessionFactoryToSet;
            // now that we have all our shard ids, construct our shard strategy
            shardStrategy = shardStrategyFactory.NewShardStrategy(shardIds);
            SetupIdGenerators();
        }