IEnumerable <Type> GetEntityTypes(IEnumerable <Type> rootEntityTypes, MatchEntities matchEntities)
        {
            using (Profiler.Step("GettingEntityTypes"))
            {
                var typesToBeChecked = new Queue <Type>(rootEntityTypes);

                var checkedTypes = new HashSet <Type>();
                var entityTypes  = new HashSet <Type>();

                do
                {
                    var typeToBeChecked = typesToBeChecked.Dequeue();

                    if ((matchEntities ?? MatchEntities.All).IsEntityMatch(typeToBeChecked))
                    {
                        entityTypes.Add(typeToBeChecked);
                    }

                    if (matchEntities != null)
                    {
                        var relatedEntities = typeToBeChecked.GetAllMembers()
                                              .Where(m => m.IsReadOnlyField() == false)
                                              .Select(m => m.ReturnType())
                                              .Where(m => m != null)
                                              .Select(t => t.GetTypeOrGenericArgumentTypeForICollection())
                                              .Select(t => t.GetTypeOrGenericArgumentTypeForIQueryable())
                                              .Where(m => m != null);

                        foreach (var e in relatedEntities)
                        {
                            if (matchEntities.IsEntityMatch(e))
                            {
                                entityTypes.Add(e);
                            }

                            if (checkedTypes.Add(e))
                            {
                                typesToBeChecked.Enqueue(e);
                            }
                        }
                    }
                } while (typesToBeChecked.Any());
                return(entityTypes);
            }
        }
        public Configuration MapEntities(IEnumerable <Type> rootEntityTypes, MatchEntities matchEntities = null,
                                         Action <hibernatemapping> applyCustomMappings = null)
        {
            var entityTypes = GetEntityTypes(rootEntityTypes, matchEntities);

            var mappingXDoc = new hibernatemapping(); //this creates the mapping xml document

            //create class xml elements for each entity type
            foreach (var type in entityTypes)
            {
                var @class = new @class()
                {
                    name  = type.AssemblyQualifiedName,
                    table = type.Name.Pluralize(), //pluralized table names - could easily have checked for a [TableName("SomeTable")] attribute for custom overrides
                };
                [email protected](@class);
            }

            var conventions =
                GetAll <IClassConvention>() //get all the conventions from the current project
                .TopologicalSort()          //sort them into a dependency tree
                .ToList();

            using (Profiler.Step("Running conventions"))
            {
                //run througn all the conventions, updating the document as we go
                foreach (var convention in conventions)
                {
                    using (Profiler.Step("Running convention " + convention.ToString()))
                    {
                        foreach (var type in entityTypes)
                        {
                            var @class = [email protected](c => c.name == type.AssemblyQualifiedName);
                            convention.Apply(type, @class, entityTypes, mappingXDoc);
                        }
                    }
                }
            }

            if (applyCustomMappings != null)
            {
                applyCustomMappings(mappingXDoc);
            }

            var xml = mappingXDoc.ToString();

            if (_writeToDisk)
            {
                var path = HostingEnvironment.ApplicationPhysicalPath ??
                           Path.GetDirectoryName(
                    Assembly.GetExecutingAssembly().CodeBase.Replace("file:///", "").
                    Replace("/", "\\"));
                File.WriteAllText(Path.Combine(path, "config.hbm.xml"), xml);
            }
            _cfg.AddXml(xml);


            foreach (var classConvention in conventions)
            {
                foreach (var adbo in classConvention.AuxDbObjects())
                {
                    _cfg.AddAuxiliaryDatabaseObject(adbo);
                }
            }
            return(_cfg);
        }