【问题标题】:Keeping db structure and procs in sync保持数据库结构和过程同步
【发布时间】:2009-12-31 19:59:31
【问题描述】:

我正在尝试设置一个测试数据库来运行自动化测试。我知道理想情况下我们应该使用模拟对象,但这是一个旧应用程序,这样做并不像应有的那么容易。数据库中的逻辑太多了。

无论如何,足够的背景故事。我得到了一个干净的数据库设置,测试可以加载已知数据,因此结果也是已知的。

在测试开始时,将运行一个 .sql 脚本来清空表,然后用测试数据填充它们。我看到的问题与其说是保持数据库结构同步,不如说它们不会发生太大变化(尽管那也很好),而是在开始时将所有 procs/functions 等从 dev 移动到 test测试。

是否有可以执行的 SQL 命令来执行此操作?要从 dev db 中读取 proc,并将其复制到 test db?

编辑:我实际上发现使用 SQL 管理对象效果很好。

唯一的问题是,如果有人重命名了一个项目,sql server 不会更新内部引用,它是在旧名称下创建的。有没有办法解决这个问题?

【问题讨论】:

  • 两台服务器是否相连?还是两个数据库都在同一台服务器上?换句话说,我们可以假设一个 SQL 脚本可以访问两个数据库吗?
  • 同一个服务器,不同的数据库。
  • 重命名操作使用 sp_rename,它不会触发任何 DDL 触发器,因此没有简单的方法来记录这些。但是根据您要完成的工作,为什么不只是 DROP all 在从 dev 数据库复制之前测试数据库中的函数/过程?
  • @Aaron,测试数据库是空的,但发生的事情是因为重命名不能解决根本问题。当您编写proc“新名称”时,它被创建为旧名称。真傻。

标签: sql-server stored-procedures copy smo


【解决方案1】:

您说保持“数据库结构”同步不是问题,但您接着说您需要将 procs/functions 从开发移动到测试。这些是数据库结构的一部分! IAC,我建议使用像 Red-Gate's SQL Compare 这样的工具。它将移动存在于 dev 上但在测试中不存在的任何数据库结构。非常好的工具。我已经用了很多年了。

【讨论】:

  • @Randy,当我说“结构”时,我的意思是“表结构”。我们有 SQL 比较,它工作得很好。但我想自动化这种能力。我不想知道在每次运行测试之前运行该工具来检查数据库结构是否相同。我希望通过调用将 procs 从 1 db 复制到另一个的 proc 来在 .NET 代码中处理此检查。
  • @Chad - 您是否知道 SQL 比较可以从命令行运行,因此可以自动运行?
  • @Randy - 它没有安装在任何地方。
【解决方案2】:

Chad,我不确定您希望如何实现自动化。如果您想一次编写所有过程的脚本,您可以从 SQL 企业管理器中完成。

在每个测试脚本之前,来自 Dev for CREATE 的所有 procs。将您的 procs 放入 TEST 并从 dev 文件运行脚本。这将确保您的 proc 同步。

【讨论】:

    【解决方案3】:

    这是一个快速而简单的 SQL 脚本,可用于将存储过程从一个数据库复制到另一个数据库:

    USE DestinationDatabase
    
    GO
    
    DECLARE
        @SchemaName sysname,
        @ProcName nvarchar(4000),
        @ProcDefinition nvarchar(max),
        @DropSql nvarchar(4000)
    
    SET @SchemaName = 'dbo'
    
    DECLARE crProcedures CURSOR FAST_FORWARD FOR
        SELECT r.ROUTINE_NAME, r.ROUTINE_DEFINITION
        FROM SourceDatabase.INFORMATION_SCHEMA.Routines r
        WHERE ROUTINE_SCHEMA = @SchemaName
        AND ROUTINE_NAME IN ('Procedure1', 'Procedure2', 'Procedure3')
    OPEN crProcedures
    FETCH NEXT FROM crProcedures INTO @ProcName, @ProcDefinition
    WHILE (@@FETCH_STATUS = 0)
    BEGIN
        SET @DropSql = 'IF  EXISTS ' +
            '(SELECT * FROM sys.objects ' +
            'WHERE object_id = OBJECT_ID(N''' + @ProcName + ''') ' +
            'AND type in (N''P'', N''PC'')) ' +
            'DROP PROCEDURE ' + @ProcName
        EXEC sp_executesql @DropSql
        EXEC sp_executesql @ProcDefinition
    
        FETCH NEXT FROM crProcedures INTO @ProcName, @ProcDefinition
    END
    CLOSE crProcedures
    DEALLOCATE crProcedures
    

    请确保不要混淆SourceDatabaseDestinationDatabase,否则会遇到麻烦!

    【讨论】:

      【解决方案4】:

      使用 SMO,以下效果非常好!并在约 40 秒内复制。

          private static void CopyDBSchema(string sourceDBServer, string sourceDBName, string targetDBServer, string targetDBName)
          {
              Server server = new Server(sourceDBServer);
              server.SetDefaultInitFields(true);
      
              Database db = server.Databases[sourceDBName];
              Transfer t = new Transfer()
              {
                  Database = db,
      
                  CopyData = false,
                  CopyAllObjects = false,
                  CopyAllUsers = false,
                  CopyAllLogins = false,
      
                  CopySchema = true,
                  CopyAllTables = true,
                  CopyAllViews = true,
                  CopyAllStoredProcedures = true,
                  CopyAllDatabaseTriggers = true,
                  CopyAllUserDefinedAggregates = true,
                  CopyAllUserDefinedDataTypes = true,
                  CopyAllUserDefinedFunctions = true,
                  CopyAllUserDefinedTypes = true,
      
                  DropDestinationObjectsFirst = true,
                  UseDestinationTransaction = true,
                  DestinationServer = targetDBServer,
                  DestinationDatabase = targetDBName
              };
      
              t.Options.WithDependencies = true;
              t.Options.IncludeIfNotExists = true;
              t.Options.DriPrimaryKey = true;
              t.Options.DriForeignKeys = true;
              t.Options.DriIndexes = true;
              t.Options.DriNonClustered = true;
              t.Options.DriUniqueKeys = true;
              t.Options.DriAllKeys = true;
              t.Options.Triggers = true;
      
              t.TransferData();
              server = null;
          }
      

      【讨论】:

      • 实际上,它正在复制所有内容,除了密钥由于某种原因没有设置身份。
      • 需要应用服务包
      猜你喜欢
      • 2019-01-09
      • 1970-01-01
      • 2010-09-14
      • 1970-01-01
      • 2010-10-29
      • 1970-01-01
      • 2015-06-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多