VS2010 Macro / Add In для команд «Run» и «Run On» в Visual Studio 2010

К большому раздражению многих разработчиков Microsoft удалила команды «Запустить» и «Запустить» в Visual Studio 2010:

Подробнее см .: http://social.msdn.microsoft.com/Forums/en/vstsdb/thread/f374c604-a7eb-496d-a261-9374790cdbf9.

Кто-нибудь видел или писал макрос VS2010 или расширение, которое заполняет пробелы и реплицирует эту функциональность?

ОК, поэтому я сдался и написал свой собственный макрос, заранее извинившись, что мои знания VB.Net были близки к несуществующим, когда я начал. Были также несколько классов, которые я раньше не использовал, прежде чем приносить извинения, если есть некоторые виды использования, которые не являются правильными или могут быть улучшены.

После того, как вы настроите контекстные меню в Visual Studio, вы можете просто щелкнуть правой кнопкой мыши по сценарию / сценариям / папке и выбрать «Run On …», и все сценарии будут запущены в выбранной базе данных. Существуют инструкции по настройке макроса и созданию контекстных меню внизу этого сообщения.

Не стесняйтесь публиковать любые исправления, и я попытаюсь обновить свой пост.

Imports System Imports EnvDTE Imports EnvDTE80 Imports EnvDTE90 Imports EnvDTE90a Imports EnvDTE100 Imports System.IO Imports System.Data.SqlClient Imports Microsoft.SqlServer.Management.Smo Imports Microsoft.SqlServer.Management.Common Imports System.Collections.Generic Imports System.Windows.Forms Public Module ContextMenu ' Copy the following files from: C:\Program Files\Microsoft SQL Server\100\SDK\Assemblies\ ' to: C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies ' ' Microsoft.SqlServer.Smo.dll ' Microsoft.SqlServer.ConnectionInfo.dll ' Microsoft.SqlServerManagement.Sdk.Sfc.dll ' ' Add a reference to them in your Macros project ' ' Add a references to ' System.Data.dll ' System.Drawing.dll Dim WithEvents _connection As SqlConnection Dim _lastError As String Dim _fileNames As New Collection Dim _errorCount As Int16 Dim _databaseOutputPane As OutputWindowPane Public Sub RunOnServer() Dim serverName As String Dim databaseName As String Dim fileName As String Dim scriptError As String 'On Error GoTo ErrHandler 'Rest global variables since macro last run! _errorCount = 0 _fileNames.Clear() _lastError = String.Empty Try _databaseOutputPane = GetDatabaseOutputPane() GetAllSelectedFiles() If Not ScriptsSelectedOk() Then Exit Sub If Not SelectServer(serverName, databaseName) Then Exit Sub If Not ValidateDatabaseConnection(serverName, databaseName) Then Exit Sub WriteToOutputWindow(Environment.NewLine) WriteToOutputWindow(String.Format("------ Running SQL scripts on '{0}' ------", serverName)) 'Iterating through all selected items (for some reason the list is upside down) For i = _fileNames.Count To 1 Step -1 fileName = _fileNames(i) If Path.GetExtension(fileName) = ".sql" Then Try scriptError = RunScript(serverName, databaseName, fileName) If Len(scriptError) > 0 Then If (ResumeRunningScripts(_lastError, fileName) = False) Then Exit For End If End If Catch ex As Exception ' Any unexpected errors not caught by the Sub Connection_InfoMessage() Dim message As String = String.Format("Do you wish to continue" + Environment.NewLine + "Error running script {0} {1} {2}", fileName, Str$(ex.Message), ex.StackTrace) Dim result = MsgBox(message, MsgBoxStyle.YesNo, "Error Running Sql Script") If result <> MsgBoxResult.Yes Then Exit For End If End Try End If Next DisplayResults() Catch ex As Exception Dim message As String = "An unexpected error occurred." + Environment.NewLine + ex.Message + vbCrLf + ex.StackTrace MessageBox.Show(message, "Run On...", MessageBoxButtons.OK, MessageBoxIcon.Error) End Try End Sub Private Function GetConnectionString(ByVal serverName As String, ByVal databaseName As String) Return String.Format("Database={0};Server={1};Trusted_Connection=True", databaseName, serverName) End Function Private Function RunScript(ByVal serverName As String, ByVal databaseName As String, ByVal fileName As String) As String Dim connectionString As String = GetConnectionString(serverName, databaseName) Dim script As String Dim server As Server WriteToOutputWindow(fileName) Try Using reader As New StreamReader(fileName) script = reader.ReadToEnd() End Using _lastError = vbNullString _connection = New SqlConnection(connectionString) ' Any errors fire the event Connection_InfoMessage _connection.FireInfoMessageEventOnUserErrors = True server = New Server(New ServerConnection(_connection)) Dim rowsAffected As Integer = server.ConnectionContext.ExecuteNonQuery(script) Finally server.ConnectionContext.Disconnect() _connection.Close() '_connection.ClearAllPools() End Try Return _lastError End Function Private Sub Connection_InfoMessage(ByVal sender As Object, ByVal e As System.Data.SqlClient.SqlInfoMessageEventArgs) Handles _connection.InfoMessage Dim err As SqlError For Each err In e.Errors _errorCount = _errorCount + 1 Dim errorMessage As String = String.Format("Msg {0}, Level {1}, State {2}, Line {3}" + Environment.NewLine + "{4}", _ err.Number, err.Class, err.State, err.LineNumber, err.Message) _lastError = _lastError & Environment.NewLine & errorMessage WriteToOutputWindow(vbCr) WriteToOutputWindow(errorMessage) Next End Sub Private Function ResumeRunningScripts(ByVal ErrorMessage As String, ByVal fileName As String) As Boolean Dim result As MsgBoxResult Dim message As String = String.Format("An error occured running the script '{0}', see output window for further details.{1}Do you wish to continue?", Path.GetFileName(fileName), Environment.NewLine) result = MsgBox(message, MsgBoxStyle.YesNo, "Error Running Sql Script") Return (result = MsgBoxResult.Yes) End Function Private Function SelectServer(ByRef serverName, ByRef databaseName) As Boolean Dim serverList As String() = New String() {"DEVDB", "STAGEDB", "LIVEDB"} Dim frm As New Form Dim cboServers As New ComboBox Dim lblServer As New Label Dim btnOk As New Button Dim btnCancel As New Button Dim lblDatabase As New Label Dim txtDatabase As New TextBox ' ' cboServers ' cboServers.FormattingEnabled = True cboServers.Items.AddRange(serverList) cboServers.Location = New System.Drawing.Point(99, 13) cboServers.Size = New System.Drawing.Size(189, 21) cboServers.TabIndex = 0 cboServers.Name = "cboServers" cboServers.SelectedIndex = 0 ' ' lblServer ' lblServer.AutoSize = True lblServer.Location = New System.Drawing.Point(12, 16) lblServer.Name = "lblServer" lblServer.Size = New System.Drawing.Size(70, 13) lblServer.Text = "Server name:" ' ' btnOk ' btnOk.DialogResult = DialogResult.OK btnOk.Location = New System.Drawing.Point(132, 69) btnOk.Size = New System.Drawing.Size(75, 23) btnOk.TabIndex = 3 btnOk.Text = "OK" ' ' btnCancel ' btnCancel.DialogResult = DialogResult.Cancel btnCancel.Size = New System.Drawing.Size(75, 23) btnCancel.Location = New System.Drawing.Point(212, 69) btnCancel.TabIndex = 4 btnCancel.Text = "Cancel" ' ' lblDatabase ' lblDatabase.AutoSize = True lblDatabase.Location = New System.Drawing.Point(12, 46) lblDatabase.Size = New System.Drawing.Size(70, 13) lblDatabase.Text = "Database:" ' ' txtDatabase ' txtDatabase.Location = New System.Drawing.Point(99, 43) txtDatabase.Size = New System.Drawing.Size(189, 20) txtDatabase.Text = "MyDatabaseName" txtDatabase.TabIndex = 2 ' ' frm ' frm.AutoScaleDimensions = New System.Drawing.SizeF(6.0F, 13.0F) frm.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font frm.Text = "Select Server" frm.Size = New System.Drawing.Size(299, 128) frm.AcceptButton = btnOk frm.CancelButton = btnCancel frm.FormBorderStyle = FormBorderStyle.FixedDialog frm.StartPosition = FormStartPosition.CenterParent frm.Controls.Add(btnCancel) frm.Controls.Add(btnOk) frm.Controls.Add(lblServer) frm.Controls.Add(cboServers) frm.Controls.Add(txtDatabase) frm.Controls.Add(lblDatabase) Dim winptr As New WinWrapper() Dim result As String ' Launch server/database dialog Try If frm.ShowDialog(winptr) = DialogResult.OK Then If Not cboServers.SelectedItem Is Nothing Then serverName = cboServers.SelectedItem Else serverName = cboServers.Text End If databaseName = txtDatabase.Text Else serverName = vbNullString databaseName = vbNullString End If SelectServer = (Len(serverName & databaseName) > 0) Catch ex As Exception frm.Close() Finally winptr = Nothing End Try End Function Public Function CreateServerForm(ByVal serverList As String()) As Form Dim frm As New Form Dim cboServers As New ComboBox Dim lblServer As New Label Dim btnOk As New Button Dim btnCancel As New Button Dim lblDatabase As New Label Dim txtDatabase As New TextBox ' ' cboServers ' cboServers.FormattingEnabled = True cboServers.Items.AddRange(serverList) cboServers.Location = New System.Drawing.Point(99, 13) cboServers.Size = New System.Drawing.Size(189, 21) cboServers.TabIndex = 0 cboServers.SelectedIndex = 0 ' ' lblServer ' lblServer.AutoSize = True lblServer.Location = New System.Drawing.Point(12, 16) lblServer.Name = "lblServer" lblServer.Size = New System.Drawing.Size(70, 13) lblServer.Text = "Server name:" ' ' btnOk ' btnOk.DialogResult = DialogResult.OK btnOk.Location = New System.Drawing.Point(132, 69) btnOk.Size = New System.Drawing.Size(75, 23) btnOk.TabIndex = 3 btnOk.Text = "OK" ' ' btnCancel ' btnCancel.DialogResult = DialogResult.Cancel btnCancel.Size = New System.Drawing.Size(75, 23) btnCancel.Location = New System.Drawing.Point(212, 69) btnCancel.TabIndex = 4 btnCancel.Text = "Cancel" ' ' lblDatabase ' lblDatabase.AutoSize = True lblDatabase.Location = New System.Drawing.Point(12, 46) lblDatabase.Size = New System.Drawing.Size(70, 13) lblDatabase.Text = "Database:" ' ' txtDatabase ' txtDatabase.Location = New System.Drawing.Point(99, 43) txtDatabase.Size = New System.Drawing.Size(189, 20) txtDatabase.Text = "MyDatabaseName" txtDatabase.TabIndex = 2 ' ' frm ' frm.AutoScaleDimensions = New System.Drawing.SizeF(6.0F, 13.0F) frm.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font frm.Text = "Select Server" frm.Size = New System.Drawing.Size(299, 128) frm.AcceptButton = btnOk frm.CancelButton = btnCancel frm.FormBorderStyle = FormBorderStyle.FixedDialog frm.StartPosition = FormStartPosition.CenterParent frm.Controls.Add(btnCancel) frm.Controls.Add(btnOk) frm.Controls.Add(lblServer) frm.Controls.Add(cboServers) frm.Controls.Add(txtDatabase) frm.Controls.Add(lblDatabase) Return frm End Function Private Function ValidateDatabaseConnection(ByVal serverName As String, ByVal databaseName As String) Dim connectionString As String = GetConnectionString(serverName, databaseName) Try Using conn = New SqlConnection(connectionString) conn.Open() End Using Return True Catch ex As Exception MessageBox.Show(String.Format("Unable to connection to the database '{0}' on server '{1}'", databaseName, serverName), "Run On...", MessageBoxButtons.OK, MessageBoxIcon.Error) Return False End Try End Function Private Function ScriptsSelectedOk() As Boolean Dim fileExtension As String Dim fileName As String ScriptsSelectedOk = True 'Iterating through all selected items For Each fileName In _fileNames fileExtension = Path.GetExtension(fileName).ToLower() If (fileExtension <> ".sql") Then ScriptsSelectedOk = False End If Next If Not ScriptsSelectedOk Then Dim result As DialogResult = MsgBox("Non-SQL scripts have been selected, do you wish to continue?", MsgBoxStyle.YesNo, "Run On...") ScriptsSelectedOk = (result = DialogResult.Yes) End If End Function Private Sub DisplayResults() WriteToOutputWindow(vbCr) WriteToOutputWindow(String.Format("Running scripts complete -- {0} errors", _errorCount)) End Sub Private Function GetDatabaseOutputPane() As OutputWindowPane Dim win As Window = DTE.Windows.Item(EnvDTE.Constants.vsWindowKindOutput) Dim ow As OutputWindow = win.Object Dim owPane As OutputWindowPane For i As Integer = 1 To ow.OutputWindowPanes.Count If (ow.OutputWindowPanes.Item(i).Name = "Database Output") Then owPane = ow.OutputWindowPanes.Item(i) owPane.Activate() Return owPane End If Next End Function Private Sub WriteToOutputWindow(ByVal message As String) _databaseOutputPane.OutputString(message) _databaseOutputPane.OutputString(vbLf) End Sub Private Sub GetAllSelectedFiles() Dim selectedItem As EnvDTE.ProjectItem Dim solutionExplorer As UIHierarchy solutionExplorer = DTE.Windows.Item(Constants.vsext_wk_SProjectWindow).Object() 'Iterating through all selected items For Each item In solutionExplorer.SelectedItems 'Get the item selectedItem = CType(item.Object, EnvDTE.ProjectItem) If (selectedItem.ProjectItems Is Nothing OrElse selectedItem.ProjectItems.Count = 0) Then ' Single File Dim fileName As Object = selectedItem.FileNames(1) _fileNames.Add(fileName) Else ' Folder NavigateProjectItems(selectedItem.ProjectItems) End If Next End Sub Private Sub NavigateProjectItems(ByVal colProjectItems As ProjectItems) Dim objProjectItem As EnvDTE.ProjectItem Dim sMsg As String If Not (colProjectItems Is Nothing) Then For Each objProjectItem In colProjectItems If Not (objProjectItem.SubProject Is Nothing) Then ' We navigate recursively because it can be: ' - An Enterprise project in VS.NET 2002/2003 ' - A solution folder in VS 2005 NavigateProject(objProjectItem.SubProject) Else Dim fileName As Object = objProjectItem.FileNames(1) ' Exclude folders If Right(fileName, 1) <> "\" Then _fileNames.Add(fileName) End If ' We navigate recursively because it can be: ' - An folder inside a project ' - A project item with nested project items (code-behind files, etc.) NavigateProjectItems(objProjectItem.ProjectItems) End If Next End If End Sub Private Sub NavigateProject(ByVal objProject As Project) Dim sMsg As String Dim objParentProjectItem As ProjectItem Try objParentProjectItem = objProject.ParentProjectItem Catch End Try NavigateProjectItems(objProject.ProjectItems) End Sub End Module '' This class is used to set the proper parent to any UI that you may display from within a macro. '' See the AddClassicComRef macro for an example of how this is used Public Class WinWrapper Implements System.Windows.Forms.IWin32Window Overridable ReadOnly Property Handle() As System.IntPtr Implements System.Windows.Forms.IWin32Window.Handle Get Dim iptr As New System.IntPtr(DTE.MainWindow.HWnd) Return iptr End Get End Property End Class 

Установите макрос в VS IDE

  • Вам нужно создать файл макроса с указанным выше кодом и вызвать его ContextMenu.vb
  • Сохраните его в% USERPROFILE% \ Documents \ Visual Studio 2010 \ Projects \ VSMacros80 \ MyMacros
  • В VS2010 перейдите в Инструменты> Макросы> Макросы IDE и загрузите макрос, щелкнув правой кнопкой мыши MyMacros> Добавить> Добавить существующий элемент
  • В верхней части макроса есть несколько инструкций для копирования некоторых файлов сборки и добавления ссылок. Следуйте за ними.

Настройка контекстных меню

  • Инструменты> Настроить …
  • Меню контекстного меню
  • Перейдите на вкладку «Команды»
  • Выберите переключатель «Контекстное меню»
  • Выберите «Контекстное меню проекта и решения» | Пункт 'из раскрывающегося списка
  • Нажмите кнопку «Добавить команду»
  • Выберите «Макросы» из списка «Категории»
  • Выберите «Macros.MyMacros.ContextMenu.RunOnServer»
  • Нажмите ОК.
  • Нажмите Изменить выбор
  • Измените имя на «Run On …»
  • Сделайте то же самое для «Контекстного меню проекта и решения» | Папка»
  • Нажмите Закрыть

Я создал проект в VS2008, который объединит ваши файлы .sql для вас в 1 файл из нескольких каталогов … не стесняйтесь использовать: http://www.filesavr.com/V9MSV0VUE77Z0WG