private void SaveProjectFile(Project project, EfTextTemplateHost efHost, TemplateProcessor templateProcessor, string entityName, string defaultNameSpaceSuffix, string templateName)
        {
            var projectRoot = new FileInfo(project.FullName).Directory.FullName;

            var contextContents = templateProcessor.Process($"{projectRoot}\\CodeTemplates\\ReverseEngineerCodeFirst\\" + templateName, efHost);

            if (string.IsNullOrWhiteSpace(efHost.NameSpaceSuffix))
            {
                efHost.NameSpaceSuffix = defaultNameSpaceSuffix;
            }

            var modelsDirectory = GetModelSavePath(project.GetProjectDir(), efHost.NameSpaceSuffix);
            var modelFileName   = Path.Combine(modelsDirectory, entityName + efHost.NameSuffix + efHost.FileExtension);

            project.AddNewFile(modelFileName, contextContents);
        }
        public void ReverseEngineerCodeFirst(Project project)
        {
            Contract.Requires(project != null);

            try
            {
                // Show dialog with SqlClient selected by default
                var dialogFactory = _package.GetService <IVsDataConnectionDialogFactory>();
                var dialog        = dialogFactory.CreateConnectionDialog();
                dialog.AddAllSources();
                dialog.SelectedSource = new Guid("067ea0d9-ba62-43f7-9106-34930c60c528");
                var dialogResult = dialog.ShowDialog(connect: true);

                if (dialogResult != null)
                {
                    // Find connection string and provider
                    _package.DTE2.StatusBar.Text = Strings.ReverseEngineer_LoadSchema;
                    var             connection       = (DbConnection)dialogResult.GetLockedProviderObject();
                    var             connectionString = connection.ConnectionString;
                    var             providerManager  = (IVsDataProviderManager)Package.GetGlobalService(typeof(IVsDataProviderManager));
                    IVsDataProvider dp;
                    providerManager.Providers.TryGetValue(dialogResult.Provider, out dp);
                    var providerInvariant = (string)dp.GetProperty("InvariantName");

                    // Load store schema
                    var storeGenerator = new EntityStoreSchemaGenerator(providerInvariant, connectionString, "dbo");
                    storeGenerator.GenerateForeignKeyProperties = true;
                    var errors = storeGenerator.GenerateStoreMetadata(_storeMetadataFilters).Where(e => e.Severity == EdmSchemaErrorSeverity.Error);
                    errors.HandleErrors(Strings.ReverseEngineer_SchemaError);

                    // Generate default mapping
                    _package.DTE2.StatusBar.Text = Strings.ReverseEngineer_GenerateMapping;
                    var contextName    = connection.Database.Replace(" ", string.Empty).Replace(".", string.Empty) + "Context";
                    var modelGenerator = new EntityModelSchemaGenerator(storeGenerator.EntityContainer, "DefaultNamespace", contextName);
                    modelGenerator.PluralizationService         = PluralizationService.CreateService(new CultureInfo("en"));
                    modelGenerator.GenerateForeignKeyProperties = true;
                    modelGenerator.GenerateMetadata();

                    // Pull out info about types to be generated
                    var entityTypes = modelGenerator.EdmItemCollection.OfType <EntityType>().ToArray();
                    var mappings    = new EdmMapping(modelGenerator, storeGenerator.StoreItemCollection);

                    // Find the project to add the code to
                    var vsProject        = (VSLangProj.VSProject)project.Object;
                    var projectDirectory = new FileInfo(project.FileName).Directory;
                    var projectNamespace = (string)project.Properties.Item("RootNamespace").Value;
                    var references       = vsProject.References.Cast <VSLangProj.Reference>();

                    if (!references.Any(r => r.Name == "EntityFramework"))
                    {
                        // Add EF References
                        _package.DTE2.StatusBar.Text = Strings.ReverseEngineer_InstallEntityFramework;

                        try
                        {
                            project.InstallPackage("EntityFramework");
                        }
                        catch (Exception ex)
                        {
                            _package.LogError(Strings.ReverseEngineer_InstallEntityFrameworkError, ex);
                        }
                    }

                    // Generate Entity Classes and Mappings
                    _package.DTE2.StatusBar.Text = Strings.ReverseEngineer_GenerateClasses;
                    var templateProcessor      = new TemplateProcessor(project);
                    var modelsNamespace        = projectNamespace + ".Models";
                    var modelsDirectory        = Path.Combine(projectDirectory.FullName, "Models");
                    var mappingNamespace       = modelsNamespace + ".Mapping";
                    var mappingDirectory       = Path.Combine(modelsDirectory, "Mapping");
                    var entityFrameworkVersion = GetEntityFrameworkVersion(references);

                    foreach (var entityType in entityTypes)
                    {
                        // Generate the code file
                        var entityHost = new EfTextTemplateHost
                        {
                            EntityType             = entityType,
                            EntityContainer        = modelGenerator.EntityContainer,
                            Namespace              = modelsNamespace,
                            ModelsNamespace        = modelsNamespace,
                            MappingNamespace       = mappingNamespace,
                            EntityFrameworkVersion = entityFrameworkVersion,
                            TableSet = mappings.EntityMappings[entityType].Item1,
                            PropertyToColumnMappings = mappings.EntityMappings[entityType].Item2,
                            ManyToManyMappings       = mappings.ManyToManyMappings
                        };
                        var entityContents = templateProcessor.Process(Templates.EntityTemplate, entityHost);

                        var filePath = Path.Combine(modelsDirectory, entityType.Name + entityHost.FileExtension);
                        project.AddNewFile(filePath, entityContents);

                        var mappingHost = new EfTextTemplateHost
                        {
                            EntityType             = entityType,
                            EntityContainer        = modelGenerator.EntityContainer,
                            Namespace              = mappingNamespace,
                            ModelsNamespace        = modelsNamespace,
                            MappingNamespace       = mappingNamespace,
                            EntityFrameworkVersion = entityFrameworkVersion,
                            TableSet = mappings.EntityMappings[entityType].Item1,
                            PropertyToColumnMappings = mappings.EntityMappings[entityType].Item2,
                            ManyToManyMappings       = mappings.ManyToManyMappings
                        };
                        var mappingContents = templateProcessor.Process(Templates.MappingTemplate, mappingHost);

                        var mappingFilePath = Path.Combine(mappingDirectory, entityType.Name + "Map" + mappingHost.FileExtension);
                        project.AddNewFile(mappingFilePath, mappingContents);
                    }

                    // Generate Context
                    _package.DTE2.StatusBar.Text = Strings.ReverseEngineer_GenerateContext;
                    var contextHost = new EfTextTemplateHost
                    {
                        EntityContainer        = modelGenerator.EntityContainer,
                        Namespace              = modelsNamespace,
                        ModelsNamespace        = modelsNamespace,
                        MappingNamespace       = mappingNamespace,
                        EntityFrameworkVersion = entityFrameworkVersion
                    };
                    var contextContents = templateProcessor.Process(Templates.ContextTemplate, contextHost);

                    var contextFilePath = Path.Combine(modelsDirectory, modelGenerator.EntityContainer.Name + contextHost.FileExtension);
                    var contextItem     = project.AddNewFile(contextFilePath, contextContents);
                    AddConnectionStringToConfigFile(project, connectionString, providerInvariant, modelGenerator.EntityContainer.Name);

                    if (contextItem != null)
                    {
                        // Open context class when done
                        _package.DTE2.ItemOperations.OpenFile(contextFilePath);
                    }

                    _package.DTE2.StatusBar.Text = Strings.ReverseEngineer_Complete;
                }
            }
            catch (Exception exception)
            {
                _package.LogError(Strings.ReverseEngineer_Error, exception);
            }
        }
        public void ReverseEngineerCodeFirst(Project project)
        {
            DebugCheck.NotNull(project);

            try
            {
                Stopwatch watcher = new Stopwatch();
                watcher.Start();
                string connectionString      = string.Empty;
                string providerInvariant     = string.Empty;
                string databaseName          = string.Empty;
                bool   isNewConnectionString = false;

                // Show available connection string
                var existingConnections = GetConnectionstrings(project);

                Connections connectionDialog = new Connections(existingConnections.Select(x => x.Name));
                connectionDialog.ShowModal();
                if (connectionDialog.IsConnectionStringSelected)
                {
                    var selected = connectionDialog.SelectedConnectionString;

                    var selectedConnectionSetting = existingConnections.First(x => x.Name.Equals(selected));
                    providerInvariant = selectedConnectionSetting.ProviderName;
                    connectionString  = selectedConnectionSetting.ConnectionString;
                    var dbConnection = DbProviderFactories.GetFactory(providerInvariant).CreateConnection();
                    dbConnection.ConnectionString = connectionString;
                    databaseName = dbConnection.Database;
                }
                else
                {
                    // Show dialog with SqlClient selected by default
                    var dialogFactory = _package.GetService <IVsDataConnectionDialogFactory>();
                    var dialog        = dialogFactory.CreateConnectionDialog();
                    dialog.AddAllSources();
                    dialog.SelectedSource = new Guid("067ea0d9-ba62-43f7-9106-34930c60c528");
                    var dialogResult = dialog.ShowDialog(connect: true);

                    if (dialogResult != null)
                    {
                        // Find connection string and provider
                        var connection = (DbConnection)dialogResult.GetLockedProviderObject();
                        connectionString = connection.ConnectionString;
                        var             providerManager = (IVsDataProviderManager)Package.GetGlobalService(typeof(IVsDataProviderManager));
                        IVsDataProvider dp;
                        providerManager.Providers.TryGetValue(dialogResult.Provider, out dp);
                        providerInvariant     = (string)dp.GetProperty("InvariantName");
                        databaseName          = connection.Database;
                        isNewConnectionString = true;
                    }
                    else
                    {
                        // User selected not to proceed by clicking cancel or closes window.
                        return;
                    }
                }

                // Load store schema
                _package.DTE2.StatusBar.Text = Strings.ReverseEngineer_LoadingSchema;

                var storeGenerator = new EntityStoreSchemaGenerator(providerInvariant, connectionString, "dbo");
                storeGenerator.GenerateForeignKeyProperties = true;
                var errors = storeGenerator.GenerateStoreMetadata(_storeMetadataFilters).Where(e => e.Severity == EdmSchemaErrorSeverity.Error);
                errors.HandleErrors(Strings.ReverseEngineer_SchemaError);

                // Generate default mapping
                _package.DTE2.StatusBar.Text = Strings.ReverseEngineer_GenerateMapping;
                var contextName    = databaseName.Replace(" ", string.Empty).Replace(".", string.Empty) + "Context";
                var modelGenerator = new EntityModelSchemaGenerator(storeGenerator.EntityContainer, "DefaultNamespace", contextName);
                modelGenerator.PluralizationService         = PluralizationService.CreateService(new CultureInfo("en"));
                modelGenerator.GenerateForeignKeyProperties = true;
                modelGenerator.GenerateMetadata();

                // Pull out info about types to be generated
                var entityTypes = modelGenerator.EdmItemCollection.OfType <EntityType>().ToArray();
                var mappings    = new EdmMapping(modelGenerator, storeGenerator.StoreItemCollection);

                // Find the project to add the code to
                var vsProject               = (VSLangProj.VSProject)project.Object;
                var projectDirectory        = new FileInfo(project.FileName).Directory;
                var defaultProjectNameSpace = (string)project.Properties.Item("RootNamespace").Value;
                var references              = vsProject.References.Cast <VSLangProj.Reference>();

                if (!references.Any(r => r.Name == "EntityFramework"))
                {
                    // Add EF References
                    _package.DTE2.StatusBar.Text = Strings.ReverseEngineer_InstallEntityFramework;

                    try
                    {
                        project.InstallPackage("EntityFramework");
                    }
                    catch (Exception ex)
                    {
                        _package.LogError(Strings.ReverseEngineer_InstallEntityFrameworkError, ex);
                    }
                }

                // Generate Entity Classes and Mappings
                var templateProcessor             = new TemplateProcessor(project);
                var modelsNamespaceSuffixDefault  = "Models";
                var mappingNamespaceSuffixDefault = "Mappings";

                var projectNamespace = defaultProjectNameSpace;
                var modelsNamespace  = string.Concat(projectNamespace, ".", modelsNamespaceSuffixDefault);
                var mappingNamespace = string.Concat(modelsNamespace, ".", mappingNamespaceSuffixDefault);

                var modelsDirectory  = projectDirectory.FullName;
                var mappingDirectory = projectDirectory.FullName;
                var contextDirectory = projectDirectory.FullName;

                var entityFrameworkVersion = GetEntityFrameworkVersion(references);
                ConcurrentDictionary <string, string> models = new ConcurrentDictionary <string, string>();
                ConcurrentDictionary <string, string> maps   = new ConcurrentDictionary <string, string>();

                // Process the templates and generate content
                Parallel.ForEach(entityTypes, (entityType) =>
                {
                    _package.DTE2.StatusBar.Text = Strings.ReverseEngineer_GenerateClasses(entityType.Name);

                    var entityHost = new EfTextTemplateHost
                    {
                        EntityType             = entityType,
                        EntityContainer        = modelGenerator.EntityContainer,
                        Namespace              = projectNamespace,
                        ModelsNamespace        = modelsNamespace,
                        MappingNamespace       = mappingNamespace,
                        EntityFrameworkVersion = entityFrameworkVersion,
                        TableSet = mappings.EntityMappings[entityType].Item1,
                        PropertyToColumnMappings = mappings.EntityMappings[entityType].Item2,
                        ManyToManyMappings       = mappings.ManyToManyMappings
                    };


                    var entityContents = templateProcessor.Process(Templates.EntityTemplate, entityHost);

                    models.TryAdd(entityType.Name + entityHost.FileExtension, entityContents);

                    var mappingHost = new EfTextTemplateHost
                    {
                        EntityType             = entityType,
                        EntityContainer        = modelGenerator.EntityContainer,
                        Namespace              = projectNamespace,
                        ModelsNamespace        = modelsNamespace,
                        MappingNamespace       = mappingNamespace,
                        EntityFrameworkVersion = entityFrameworkVersion,
                        TableSet = mappings.EntityMappings[entityType].Item1,
                        PropertyToColumnMappings = mappings.EntityMappings[entityType].Item2,
                        ManyToManyMappings       = mappings.ManyToManyMappings
                    };

                    var mappingContents = templateProcessor.Process(Templates.MappingTemplate, mappingHost);

                    maps.TryAdd(entityType.Name + "Map" + mappingHost.FileExtension, mappingContents);
                });

                // Generate Context
                _package.DTE2.StatusBar.Text = Strings.ReverseEngineer_GenerateContext;
                var contextHost = new EfTextTemplateHost
                {
                    EntityContainer        = modelGenerator.EntityContainer,
                    Namespace              = projectNamespace,
                    ModelsNamespace        = modelsNamespace,
                    MappingNamespace       = mappingNamespace,
                    EntityFrameworkVersion = entityFrameworkVersion
                };

                var contextContents = templateProcessor.Process(Templates.ContextTemplate, contextHost);

                ProjectFilesPathGenUtility.SyncDirectoryWithNamespace(
                    defaultProjectNameSpace,
                    contextHost.Namespace,
                    modelsNamespaceSuffixDefault,
                    projectDirectory.FullName,
                    ref contextDirectory);

                var contextFilePath = Path.Combine(contextDirectory, modelGenerator.EntityContainer.Name + contextHost.FileExtension);

                _package.DTE2.StatusBar.Text = Strings.ReverseEngineer_AddingFiles;
                var contextItem = project.AddNewFile(contextFilePath, contextContents);

                // sync model directory
                ProjectFilesPathGenUtility.SyncDirectoryWithNamespace(
                    defaultProjectNameSpace,
                    contextHost.ModelsNamespace,
                    modelsNamespaceSuffixDefault,
                    projectDirectory.FullName,
                    ref modelsDirectory);

                // Add models
                Parallel.ForEach(models, (file) =>
                {
                    project.AddNewFile(Path.Combine(modelsDirectory, file.Key), file.Value);
                });

                // sync project mapping directory
                ProjectFilesPathGenUtility.SyncDirectoryWithNamespace(
                    defaultProjectNameSpace,
                    contextHost.MappingNamespace,
                    mappingNamespaceSuffixDefault,
                    projectDirectory.FullName,
                    ref mappingDirectory);

                // Add mappings
                Parallel.ForEach(maps, (file) =>
                {
                    project.AddNewFile(Path.Combine(mappingDirectory, file.Key), file.Value);
                });

                if (isNewConnectionString)
                {
                    AddConnectionStringToConfigFile(project, connectionString, providerInvariant, modelGenerator.EntityContainer.Name);
                }

                if (contextItem != null)
                {
                    // Open context class when done
                    _package.DTE2.ItemOperations.OpenFile(contextFilePath);
                }

                watcher.Stop();
                _package.DTE2.StatusBar.Text = Strings.ReverseEngineer_Complete((int)watcher.Elapsed.TotalSeconds);
            }
            catch (Exception exception)
            {
                _package.LogError(Strings.ReverseEngineer_Error, exception);
            }
        }
        public void ReverseEngineerCodeFirst(Project project)
        {
            DebugCheck.NotNull(project);

            try
            {
                // Show dialog with SqlClient selected by default
                var dialogFactory = _package.GetService<IVsDataConnectionDialogFactory>();
                var dialog = dialogFactory.CreateConnectionDialog();
                dialog.AddAllSources();
                dialog.SelectedSource = new Guid("067ea0d9-ba62-43f7-9106-34930c60c528");
                var dialogResult = dialog.ShowDialog(connect: true);

                if (dialogResult != null)
                {
                    // Find connection string and provider
                    _package.DTE2.StatusBar.Text = Strings.ReverseEngineer_LoadSchema;
                    var connection = (DbConnection)dialogResult.GetLockedProviderObject();
                    var connectionString = connection.ConnectionString;
                    var providerManager = (IVsDataProviderManager)Package.GetGlobalService(typeof(IVsDataProviderManager));
                    IVsDataProvider dp;
                    providerManager.Providers.TryGetValue(dialogResult.Provider, out dp);
                    var providerInvariant = (string)dp.GetProperty("InvariantName");

                    // Load store schema
                    var storeGenerator = new EntityStoreSchemaGenerator(providerInvariant, connectionString, "dbo");
                    storeGenerator.GenerateForeignKeyProperties = true;
                    var errors = storeGenerator.GenerateStoreMetadata(_storeMetadataFilters).Where(e => e.Severity == EdmSchemaErrorSeverity.Error);
                    errors.HandleErrors(Strings.ReverseEngineer_SchemaError);

                    // Generate default mapping
                    _package.DTE2.StatusBar.Text = Strings.ReverseEngineer_GenerateMapping;
                    var contextName = connection.Database.Replace(" ", string.Empty).Replace(".", string.Empty) + "Context";
                    var modelGenerator = new EntityModelSchemaGenerator(storeGenerator.EntityContainer, "DefaultNamespace", contextName);
                    modelGenerator.PluralizationService = PluralizationService.CreateService(new CultureInfo("en"));
                    modelGenerator.GenerateForeignKeyProperties = true;
                    modelGenerator.GenerateMetadata();

                    // Pull out info about types to be generated
                    var entityTypes = modelGenerator.EdmItemCollection.OfType<EntityType>().ToArray();
                    var mappings = new EdmMapping(modelGenerator, storeGenerator.StoreItemCollection);

                    // Find the project to add the code to
                    var vsProject = (VSLangProj.VSProject)project.Object;
                    var projectDirectory = new FileInfo(project.FileName).Directory;
                    var projectNamespace = (string)project.Properties.Item("RootNamespace").Value;
                    var references = vsProject.References.Cast<VSLangProj.Reference>();

                    if (!references.Any(r => r.Name == "EntityFramework"))
                    {
                        // Add EF References
                        _package.DTE2.StatusBar.Text = Strings.ReverseEngineer_InstallEntityFramework;

                        try
                        {
                            project.InstallPackage("EntityFramework");
                        }
                        catch (Exception ex)
                        {
                            _package.LogError(Strings.ReverseEngineer_InstallEntityFrameworkError, ex);
                        }
                    }

                    // Generate Entity Classes and Mappings
                    _package.DTE2.StatusBar.Text = Strings.ReverseEngineer_GenerateClasses;
                    var templateProcessor = new TemplateProcessor(project);
                    var modelsNamespace = projectNamespace + ".Models";
                    var modelsDirectory = Path.Combine(projectDirectory.FullName, "Models");
                    var mappingNamespace = modelsNamespace + ".Mapping";
                    var mappingDirectory = Path.Combine(modelsDirectory, "Mapping");
                    var entityFrameworkVersion = GetEntityFrameworkVersion(references);

                    foreach (var entityType in entityTypes)
                    {
                        // Generate the code file
                        var entityHost = new EfTextTemplateHost
                            {
                                EntityType = entityType,
                                EntityContainer = modelGenerator.EntityContainer,
                                Namespace = modelsNamespace,
                                ModelsNamespace = modelsNamespace,
                                MappingNamespace = mappingNamespace,
                                EntityFrameworkVersion = entityFrameworkVersion,
                                TableSet = mappings.EntityMappings[entityType].Item1,
                                PropertyToColumnMappings = mappings.EntityMappings[entityType].Item2,
                                ManyToManyMappings = mappings.ManyToManyMappings
                            };
                        var entityContents = templateProcessor.Process(Templates.EntityTemplate, entityHost);

                        var filePath = Path.Combine(modelsDirectory, entityType.Name + entityHost.FileExtension);
                        project.AddNewFile(filePath, entityContents);

                        var mappingHost = new EfTextTemplateHost
                            {
                                EntityType = entityType,
                                EntityContainer = modelGenerator.EntityContainer,
                                Namespace = mappingNamespace,
                                ModelsNamespace = modelsNamespace,
                                MappingNamespace = mappingNamespace,
                                EntityFrameworkVersion = entityFrameworkVersion,
                                TableSet = mappings.EntityMappings[entityType].Item1,
                                PropertyToColumnMappings = mappings.EntityMappings[entityType].Item2,
                                ManyToManyMappings = mappings.ManyToManyMappings
                            };
                        var mappingContents = templateProcessor.Process(Templates.MappingTemplate, mappingHost);

                        var mappingFilePath = Path.Combine(mappingDirectory, entityType.Name + "Map" + mappingHost.FileExtension);
                        project.AddNewFile(mappingFilePath, mappingContents);
                    }

                    // Generate Context
                    _package.DTE2.StatusBar.Text = Strings.ReverseEngineer_GenerateContext;
                    var contextHost = new EfTextTemplateHost
                        {
                            EntityContainer = modelGenerator.EntityContainer,
                            Namespace = modelsNamespace,
                            ModelsNamespace = modelsNamespace,
                            MappingNamespace = mappingNamespace,
                            EntityFrameworkVersion = entityFrameworkVersion
                        };
                    var contextContents = templateProcessor.Process(Templates.ContextTemplate, contextHost);

                    var contextFilePath = Path.Combine(modelsDirectory, modelGenerator.EntityContainer.Name + contextHost.FileExtension);
                    var contextItem = project.AddNewFile(contextFilePath, contextContents);
                    AddConnectionStringToConfigFile(project, connectionString, providerInvariant, modelGenerator.EntityContainer.Name);

                    if (contextItem != null)
                    {
                        // Open context class when done
                        _package.DTE2.ItemOperations.OpenFile(contextFilePath);
                    }

                    _package.DTE2.StatusBar.Text = Strings.ReverseEngineer_Complete;
                }
            }
            catch (Exception exception)
            {
                _package.LogError(Strings.ReverseEngineer_Error, exception);
            }
        }