【问题标题】:Database changes versioning数据库更改版本控制
【发布时间】:2016-10-08 22:00:08
【问题描述】:

我的问题是我找不到如何从命令行更新 sqlproj 以跟踪存储库中的数据库更改的方法。根据this post:“此版本不直接支持的项目”,但是尝试了下一个命令但没有成功:

msbuild PathToMyProject.sqlproj /t:SqlSchemaCompare /p:SqlScmpFilePath=SomePath/ComparationConfiguration.scmp /p:target=PathToMyProject.sqlproj /p:Deploy="true"

并且找不到如何执行此操作的方法。有可能吗?
从另一方面看,我可以将数据库模式与 dacpac 文件(sqlproj 的编译输出)进行比较,以获取数据库项目中不存在的更改,但是对于数据库更改跟踪的自动化,它看起来没用,因为每次我得到一些更改时,我需要手动打开相关解决方案,进行比较,更新目标数据库项目,然后检查对存储库的更改

【问题讨论】:

    标签: database msbuild sql-server-data-tools


    【解决方案1】:

    没有命令行支持从数据库自动更新数据库项目。这主要是因为 SSDT 旨在启用的工作流是离线数据库开发:期望首先对数据库项目进行更改,然后再发布到数据库。

    【讨论】:

    • 你好史蒂文,谢谢你的回答。不确定 Visual Studio 数据库项目更新功能(“工具 > SQL Server > 新架构比较...”)是否完全基于 SSDT,但对我来说,使用 VS UI 可以更新它(sqlproj)看起来有点奇怪,但不能使用命令行执行此操作。
    • @Vova - 我怀疑 UI 功能的存在是为了识别有时可以“脱离进程”(通常称为“漂移”)进行更改,这提供了一种将更改复制回的机制dev 的真实来源,版本控制中的数据库项目。
    【解决方案2】:

    正如@Steven Green 在另一个答案中所说,目前无法从命令行使用 SSDT 更新数据库项目(希望它很快可用),但是已经找到了另一种在没有数据库项目的情况下版本数据库架构更改的方法(已将其留到将来,以防添加任何更新它的命令行方法)。解决方案基于使用SMO 生成数据库模式创建sql 脚本的C# 程序。因此,我们只需将此脚本存储在存储库中,并使用运行检查的 CI 服务器配置每天更新,以防发现任何更改 - 将它们提交到存储库中。将这些步骤留给遇到同样问题的人:

    1. 需要参考下一个依赖项(我的位于 C:\Program Files (x86)\Microsoft SQL Server\130\SDK\Assemblies):

      • Microsoft.SqlServer.ConnectionInfo.dll
      • Microsoft.SqlServer.Management.Sdk.Sfc.dll
      • Microsoft.SqlServer.Smo.dll
      • Microsoft.SqlServer.SmoExtended.dll
    2. 使用下一个代码生成文件:

      using System;
      using System.Configuration;
      using System.Data.SqlClient;
      using System.IO;
      using System.Text;
      using Microsoft.SqlServer.Management.Common;
      using Microsoft.SqlServer.Management.Smo;
      
      namespace ScriptGenerator {
          class Program {
              private static string GetTransferScript(Database database){
                  var transfer = new Transfer(database) {
                                     CopyAllObjects = true,
                                     CopyAllSynonyms = true,
                                     CopyData = false,
                                     PreserveDbo = true,
                                     Options = {
                                                   WithDependencies = true,
                                                   DriAll = true,
                                                   Triggers = true,
                                                   Indexes = true,
                                                   SchemaQualifyForeignKeysReferences = true,
                                                   ExtendedProperties = true,
                                                   IncludeDatabaseRoleMemberships = true,
                                                   Permissions = true
                                               }
      
                                 };
                  var transferScript = new StringBuilder();
                  foreach (var scriptLine in transfer.ScriptTransfer()) {
                      transferScript.AppendLine(scriptLine);
                  }
                  return transferScript.ToString();
              }
      
              static void Main(string[] args){
                  var databaseName = "yourDataseName";
                  var outputSqlFile = Path.GetFullPath($"DatabaseSchemaScript.sql");
      
                  if (File.Exists(outputSqlFile))
                      File.Delete(outputSqlFile);
      
                  using (var connection = new SqlConnection(ConfigurationManager.AppSettings["DatabaseConnectionString"])) {
                      var server = new Server(new ServerConnection(connection));
                      if (!server.Databases.Contains(databaseName))
                          throw new Exception($"Database '{databaseName}' does not exists on server{connection.DataSource}");
      
                      var database = server.Databases[databaseName];
                      var transferScript = GetTransferScript(database);
                      using (var sw = new StreamWriter(outputSqlFile)) {
                          sw.WriteLine(transferScript);
                      }
                  }
              }
          }
      }
      

    【讨论】:

    • 这也可以通过 SqlPackage.exe 选项 /Action:Script 从一个可以从数据库生成的 .dacpac 文件到一个空数据库来完成。仍然缺少的是从您导出的脚本生成 .sqlproj 的可能性......
    • 实际上这篇文章的主要目的是有一些自动化的数据库更改版本控制方式,考虑到 .sqlproj 因为它提供了我们能够完成版本控制的 UI,但这真的是出乎意料命令行中将无法使用相同的 UI 操作