演练:比较两个数据库的架构

本主题适用于:

Visual Studio 旗舰版

Visual Studio 高级专业版

Visual Studio 专业版 

Visual Studio 学习版

主题适用 主题适用 主题不适用 主题不适用

在本演练中,将使用 Visual Studio 比较两个数据库的架构。 架构比较操作还会从差异中生成一个数据定义语言 (DDL) 脚本。 使用此文件可以将目标数据库的架构与源数据库的架构进行同步。 有关更多信息,请参见比较和同步数据库架构

您将遵循本演练中的以下过程:

  • 创建一个简单数据库。 如果您已完成演练:比较数据库的架构和数据库项目的架构,则可以使用生成的数据库并跳过这一部分的演练。

  • 创建一个空数据库。 CompareProjectDB 数据库作为源,您创建一个空数据库作为目标。

  • 比较两个数据库的架构。 通过比较架构,您将找出数据库之间的结构差异,将其显示在表中,并生成表示这些差异的 DDL 脚本。

  • 检查同步脚本。 检查 DDL 脚本,并可以在运行它之前进行编辑。

  • 更新目标数据库。 运行 DDL 脚本来更改目标的架构。

系统必备

必须安装下列产品:

  • SQL Server 2008

  • 可在目标数据库服务器上创建和更新数据库的权限

  • Visual Studio 高级专业版或 Visual Studio 旗舰版

创建一个简单数据库

您将通过执行以下任务来创建一个简单的数据库:

  • 创建包含数据库架构的脚本

  • 创建数据库项目并导入该架构

  • 将数据库项目部署到独立开发环境中

创建包含数据库架构的脚本

创建可从中导入架构的脚本

  1. 在**“文件”菜单上指向“新建”,然后单击“文件”**。

    此时出现**“新建文件”**对话框。

  2. 在**“类别”列表中,如果尚未突出显示“常规”**,请单击它。

  3. 在**“模板”列表中,单击“Sql 文件”,然后单击“打开”**。

    Transact-SQL 编辑器打开。

  4. 复制下面的 Transact-SQL 代码并将其粘贴到 Transact-SQL 编辑器中。

    PRINT N'Creating Sales...';
    GO
    CREATE SCHEMA [Sales]
        AUTHORIZATION [dbo];
    GO
    PRINT N'Creating Sales.Customer...';
    GO
    CREATE TABLE [Sales].[Customer] (
        [CustomerID]   INT IDENTITY (1, 1) NOT NULL,
        [CustomerName] NVARCHAR (40) NOT NULL,
        [YTDOrders] INT NOT NULL,
        [YTDSales] INT NOT NULL
    );
    GO
    PRINT N'Creating Sales.Orders...';
    GO
    CREATE TABLE [Sales].[Orders] (
        [CustomerID] INT NOT NULL,
        [OrderID] INT IDENTITY (1, 1) NOT NULL,
        [OrderDate] DATETIME NOT NULL,
        [FilledDate] DATETIME NULL,
        [Status] CHAR (1) NOT NULL,
        [Amount] INT NOT NULL
    );
    GO
    PRINT N'Creating Sales.Def_Customer_YTDOrders...';
    GO
    ALTER TABLE [Sales].[Customer]
        ADD CONSTRAINT [Def_Customer_YTDOrders] DEFAULT 0 FOR [YTDOrders];
    GO
    PRINT N'Creating Sales.Def_Customer_YTDSales...';
    GO
    ALTER TABLE [Sales].[Customer]
        ADD CONSTRAINT [Def_Customer_YTDSales] DEFAULT 0 FOR [YTDSales];
    GO
    PRINT N'Creating Sales.Def_Orders_OrderDate...';
    GO
    ALTER TABLE [Sales].[Orders]
        ADD CONSTRAINT [Def_Orders_OrderDate] DEFAULT GetDate() FOR [OrderDate];
    GO
    PRINT N'Creating Sales.Def_Orders_Status...';
    GO
    ALTER TABLE [Sales].[Orders]
        ADD CONSTRAINT [Def_Orders_Status] DEFAULT 'O' FOR [Status];
    GO
    PRINT N'Creating Sales.PK_Customer_CustID...';
    GO
    ALTER TABLE [Sales].[Customer]
        ADD CONSTRAINT [PK_Customer_CustID] PRIMARY KEY CLUSTERED ([CustomerID] ASC) WITH (ALLOW_PAGE_LOCKS = ON, ALLOW_ROW_LOCKS = ON, PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF, STATISTICS_NORECOMPUTE = OFF);
    GO
    PRINT N'Creating Sales.PK_Orders_OrderID...';
    GO
    ALTER TABLE [Sales].[Orders]
        ADD CONSTRAINT [PK_Orders_OrderID] PRIMARY KEY CLUSTERED ([OrderID] ASC) WITH (ALLOW_PAGE_LOCKS = ON, ALLOW_ROW_LOCKS = ON, PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF, STATISTICS_NORECOMPUTE = OFF);
    GO
    PRINT N'Creating Sales.FK_Orders_Customer_CustID...';
    GO
    ALTER TABLE [Sales].[Orders]
        ADD CONSTRAINT [FK_Orders_Customer_CustID] FOREIGN KEY ([CustomerID]) REFERENCES [Sales].[Customer] ([CustomerID]) ON DELETE NO ACTION ON UPDATE NO ACTION;
    GO
    PRINT N'Creating Sales.CK_Orders_FilledDate...';
    GO
    ALTER TABLE [Sales].[Orders]
        ADD CONSTRAINT [CK_Orders_FilledDate] CHECK ((FilledDate >= OrderDate) AND (FilledDate < '01/01/2010'));
    GO
    PRINT N'Creating Sales.CK_Orders_OrderDate...';
    GO
    ALTER TABLE [Sales].[Orders]
        ADD CONSTRAINT [CK_Orders_OrderDate] CHECK ((OrderDate > '01/01/2005') and (OrderDate < '01/01/2020'));
    GO
    PRINT N'Creating Sales.uspCancelOrder...';
    GO
    CREATE PROCEDURE [Sales].[uspCancelOrder]
    @OrderID INT
    AS
    BEGIN
    DECLARE @Delta INT, @CustomerID INT
    BEGIN TRANSACTION
        SELECT @Delta = [Amount], @CustomerID = [CustomerID]
         FROM [Sales].[Orders] WHERE [OrderID] = @OrderID;
    
    UPDATE [Sales].[Orders]
       SET [Status] = 'X'
    WHERE [OrderID] = @OrderID;
    
    UPDATE [Sales].[Customer]
       SET
       YTDOrders = YTDOrders - @Delta
        WHERE [CustomerID] = @CustomerID
    COMMIT TRANSACTION
    END
    GO
    PRINT N'Creating Sales.uspFillOrder...';
    GO
    CREATE PROCEDURE [Sales].[uspFillOrder]
    @OrderID INT, @FilledDate DATETIME
    AS
    BEGIN
    DECLARE @Delta INT, @CustomerID INT
    BEGIN TRANSACTION
        SELECT @Delta = [Amount], @CustomerID = [CustomerID]
         FROM [Sales].[Orders] WHERE [OrderID] = @OrderID;
    
    UPDATE [Sales].[Orders]
       SET [Status] = 'F',
           [FilledDate] = @FilledDate
    WHERE [OrderID] = @OrderID;
    
    UPDATE [Sales].[Customer]
       SET
       YTDSales = YTDSales - @Delta
        WHERE [CustomerID] = @CustomerID
    COMMIT TRANSACTION
    END
    GO
    PRINT N'Creating Sales.uspNewCustomer...';
    GO
    CREATE PROCEDURE [Sales].[uspNewCustomer]
    @CustomerName NVARCHAR (40)
    AS
    BEGIN
    INSERT INTO [Sales].[Customer] (CustomerName) VALUES (@CustomerName);
    SELECT SCOPE_IDENTITY()
    END
    GO
    PRINT N'Creating Sales.uspPlaceNewOrder...';
    GO
    CREATE PROCEDURE [Sales].[uspPlaceNewOrder]
    @CustomerID INT, @Amount INT, @OrderDate DATETIME, @Status CHAR (1)='O'
    AS
    BEGIN
    DECLARE @RC INT
    BEGIN TRANSACTION
    INSERT INTO [Sales].[Orders] (CustomerID, OrderDate, FilledDate, Status, Amount) 
         VALUES (@CustomerID, @OrderDate, NULL, @Status, @Amount)
    SELECT @RC = SCOPE_IDENTITY();
    UPDATE [Sales].[Customer]
       SET
       YTDOrders = YTDOrders + @Amount
        WHERE [CustomerID] = @CustomerID
    COMMIT TRANSACTION
    RETURN @RC
    END
    GO
    
  5. 在**“文件”菜单上,单击“将 SqlQuery_1.sql 另存为”**。

    将出现**“另存文件为”**对话框。

  6. 在**“对象名”**中,键入 SampleImportScript.sql。

    可以将文件保存到计算机中的任何位置。 记下该位置,因为在下面的步骤中必须使用此脚本。

  7. 单击**“保存”**。

  8. 在**“文件”菜单上,单击“关闭解决方案”**。

    接下来,创建一个数据库项目,并从已创建的脚本导入架构。

创建数据库项目并导入架构

创建数据库项目

  1. 在**“文件”菜单上指向“新建”,再单击“项目”**。

    此时将出现**“新建项目”**对话框。

  2. 在**“已安装的模板”下,展开“数据库”节点,然后单击“SQL Server”**。

  3. 在模板列表中单击**“SQL Server 2008 数据库项目”**。

  4. 在**“名称”**中,键入“CompareProjectDB”。

  5. 在**“解决方案”列表中,单击“创建解决方案”**(如果该项尚未突出显示)。

  6. 如果**“创建解决方案的目录”**复选框尚未选中,则选择该复选框。

  7. 如果**“添加到源代码管理”复选框尚未清除,则清除该复选框,并单击“确定”**。

    将会创建数据库项目并将其显示在**“解决方案资源管理器”**中。 接下来,从脚本中导入数据库架构。

从脚本中导入数据库

  1. 在**“项目”菜单上,单击“导入脚本”**。

  2. 阅读“欢迎”页之后,单击**“下一步”**。

  3. 单击**“浏览”**,指出保存 SampleImportScript.sql 文件的路径。

  4. 双击 SampleImportScript.sql 文件,然后单击**“完成”**。

    将导入脚本,在该脚本中定义的对象添加到数据库项目中。

  5. 查看摘要,然后单击**“完成”**完成操作。

    提示

    Sales.uspFillOrder 过程包含一个故意设置的代码错误,您将在单元测试演练中发现该错误并加以更正。

检查产生的项目

  1. 在**“解决方案资源管理器”中,展开“架构对象”**子节点。

  2. 浏览层次结构中**“架构对象”**节点下的子节点。

    **“解决方案资源管理器”**包含定义数据库对象的文件。

  3. 在**“视图”菜单上,单击“数据库架构视图”**。

  4. 在**“架构视图”**中展开“CompareProjectDB”节点。

  5. 浏览层次结构中“CompareProjectDB”节点下的子节点。

    **“架构视图”包含“解决方案资源管理器”**中显示的文件中定义的对象。

部署到独立开发环境

接下来,部署项目以创建一个具有导入的架构但没有数据的数据库。 您将在独立开发环境(即,沙盒)中创建数据库。 因此,您可以在没有外界干扰的情况下开发和测试数据库。

配置和生成数据库项目

  1. 在**“解决方案资源管理器”**中,单击数据库项目“CompareProjectDB”。

  2. 在**“项目”菜单上,单击“CompareProjectDB 属性”**。

    即会显示该项目的属性对话框。

  3. 单击**“部署”**选项卡。

  4. 在**“配置部署设置”列表中,单击“我的独立开发环境”**。 通过为独立开发环境配置设置,可以使用不同于将在其他环境(如测试服务器或生产服务器)中使用的设置的部署设置。

  5. 在**“部署操作”列表中,单击“创建部署脚本(.sql)并部署到数据库”**。

  6. 在**“目标数据库设置”中,单击“编辑”**。

    随即出现**“连接属性”**对话框。

  7. 设置要创建的数据库的连接属性,然后单击**“确定”**。

    在**“目标连接”**框中,出现正确的连接字符串。

    警告

    应在测试服务器、开发服务器或本地计算机上创建数据库。 不应指定生产服务器。

  8. 在**“目标数据库名称”**中,键入“CompareProjectDB”。

  9. 在**“部署配置文件”旁,单击“编辑”**。

  10. 清除**“如果可能发生数据丢失则阻止增量部署”**复选框。

    提示

    对于本演练,您将针对在数据库单元测试过程中部署的空数据库来测试存储过程。 由于将在独立开发环境中测试存储过程,因此不必保留任何现有数据。

  11. 在**“文件”菜单上,单击“全部保存”**。

  12. 在**“生成”菜单上,单击“生成解决方案”**。

    刚刚设置的属性将确定生成部署脚本的方式。 生成状态显示在**“输出”窗口中,最后一行应显示“生成: 1 成功或最新”**。

部署数据库项目

  1. 在**“解决方案资源管理器”**中,单击“CompareProjectDB”数据库项目。

  2. 在**“生成”菜单上,单击“部署 CompareProjectDB”**。

    警告

    应对测试服务器、开发服务器或本地计算机运行此部署。 不应指定生产服务器。

    数据库项目部署到新数据库。 部署状态显示在**“输出”窗口中,最后一行应显示“部署已成功”**。 接下来,创建一个可与此部署的数据库进行比较的空数据库。

创建一个空数据库

创建空数据库

  1. 在**“文件”菜单上指向“新建”,再单击“项目”**。

    此时将出现**“新建项目”**对话框。

  2. 在**“已安装的模板”列表中,展开“数据库”节点,再单击“SQL Server”**。

  3. 单击**“SQL Server 2008 向导”**。

  4. 在**“名称”**中,键入 EmptyDB。

  5. 接受其余字段的默认值,然后单击**“确定”**。

  6. 在“新建数据库项目向导”中,单击**“配置生成/部署”**。

  7. 在**“部署操作”列表中,单击“创建部署脚本(.sql)并部署到数据库”**。

  8. 在**“目标连接”中,单击“浏览”**按钮。

  9. 指定与创建空数据库所用的数据库服务器的连接,然后单击**“完成”**。

    将创建一个名为“EmptyDB”的数据库项目,并将其显示在**“解决方案资源管理器”**中。

  10. 在**“解决方案资源管理器”**中,单击“EmptyDB”数据库项目。

  11. 在**“生成”菜单上,单击“部署 EmptyDB”**。

    数据库项目随即生成并部署到指定的服务器上。

比较两个数据库的架构

比较两个数据库的架构

  1. 在**“数据”菜单上,指向“架构比较”,然后单击“新建架构比较”**。

    **“新建架构比较”**对话框将出现,以便您能够指定源和目标。 在此对话框中,标识源和目标驻留的服务器、各个数据库的名称以及连接各个数据库时要使用的身份验证类型。

    另外,“架构比较”窗口还会在后台打开,并且 Visual Studio 会自动为其分配一个名称,如 SchemaCompare1。

  2. 在**“源架构”下单击“数据库”**,然后单击与 CompareProjectDB 数据库对应的连接。

    如果列表中未显示这类连接,请单击**“新建连接”。 在“连接属性”对话框中,标识 CompareProjectDB 数据库驻留的服务器、连接该数据库时要使用的身份验证类型以及该数据库本身。 完成上述操作后,单击“确定”**。

    提示

    建立连接后,该连接会出现在“服务器资源管理器”中的“数据连接”下。

  3. 在**“目标架构”下单击“数据库”**,然后单击与 EmptyDB 数据库对应的连接。

    如果列表中未显示这类连接,请单击**“新建连接”。 在“连接属性”对话框中,标识 EmptyDB 数据库驻留的服务器、连接该数据库时要使用的身份验证类型以及该数据库本身。 完成上述操作后,单击“确定”**。

  4. 单击**“选项”**,指定将比较的对象、将忽略的差异类型以及生成的更新脚本中将要包含的内容。

    提示

    当比较数据库时,不要指定 SQLCMD 变量。

  5. 在**“常规”选项卡上,展开“比较选项”**节点。

  6. 选择**“忽略文件和日志文件的文件名和路径”**。

  7. 单击**“确定”**。

  8. 单击**“确定”**。

    架构比较开始。

    提示

    通过打开“数据”菜单,指向“架构比较”,然后单击“停止架构比较”,可以停止正在进行的比较。

    可以配置选项决定差异的具体内容以及更改更新脚本的创建方式。 有关更多信息,请参见如何:设置比较数据库架构的选项

    比较完成后,两个数据库之间的结构差异将显示在“架构比较”窗口的表中。 对于这两个数据库中的每个数据库对象,表中显示一行。 数据库对象按类型组织:表、视图、存储过程、角色等。

更新目标数据库

要更新目标数据库架构,有两种选择。 可以直接从“架构比较”窗口更新架构,也可以通过使用 Transact-SQL 编辑器更新架构。 本节对这两种方法进行介绍。

运行架构比较后,结构差异显示在“架构比较”窗口的表中。 对于**“CompareProjectDB (源数据库)”列中的每个对象,该表在“更新操作”列中都会显示一个操作,此操作对同步两个数据库中的对象是必需的。 在本例中,由于目标只包含默认对象,所以“状态”列多数为“新建”状态,“更新操作”**列多数为“创建”操作。

将更新写入目标

可以使用“架构比较”窗口中列出的更新操作更新目标的架构。 要执行此任务,请按照将更新写入目标数据库中的步骤操作。

查看脚本,然后将更新写入目标

可以导出更新脚本,对其进行检查,进行可能的更改,然后用它同步目标数据库。 要执行这些任务,请按照检查并执行同步脚本中的步骤操作。

将更新写入目标数据库

提示

在将更新写入生产服务器或开发服务器之前,应考虑对目标数据库进行备份。 由于某些架构更改无法在单个事务内执行,因此,如果启动更新操作然后再将其取消,则可能会丢失数据。 例如,目标数据库中的表在准备重新创建过程中可能已被删除。 如果此时取消更新,则可能会丢失该表。 在本演练中,您将更新一个空的开发数据库。 因此,您无需备份目标数据库。

将更新写入目标数据库

  1. 在比较结果的列表中,滚动到**“SQL 文件”**节点。

  2. 对于 CompareProjectDB 文件和 CompareProjectDB_Log 文件,将更新操作从“创建”更改为“跳过”。

    提示

    如果在相同的数据库服务器上比较两个数据库,则同步过程将因目标数据和日志文件已经存在且正在由源数据库使用而失败。 对于此演练,您只需跳过对文件的更新,然后同步数据库的内容。

  3. 对于 EmptyDB 文件和 EmptyDB_log 文件,将更新操作从“删除”更改为“跳过”。

    提示

    由于您不是从源数据库创建文件,因此不得删除目标数据库的文件。 对于此演练,您只需跳过对文件的更新,然后同步数据库的内容。

  4. 在**“架构比较”工具栏上,单击“写入更新”**。

    “架构比较”窗口中列出的更新操作就会执行。 此同步将更改目标的架构使其和源的架构匹配。

    提示

    进行更新操作时,打开“数据”菜单,指向“架构比较”并单击“停止写入目标”,可以取消操作。

    如果要再次运行比较以验证是否应用了选定的更新,则可以单击**“架构比较”工具栏上的“刷新”**。

检查并执行同步脚本

检查同步脚本

  1. 在**“数据”菜单上,指向“架构比较”,然后指向“导出到”并单击“编辑器”**。

    或者,也可以单击**“架构比较”工具栏上的“导出到编辑器”**。

    Transact-SQL 编辑器将在断开连接模式下打开并显示 Transact-SQL 同步脚本。 此窗口的名称类似于 CompareProjectDB - SchemaUpdate_EmptyDB_1.sql, 其中将显示 Transact-SQL 脚本。 由于您具有此窗口的读写访问权限,因此可以更改脚本。 如果更改脚本,请打开**“文件”菜单,然后单击“保存”**。 您可以在保存文件时指定其路径和名称。

  2. 在**“Transact-SQL 编辑器”工具栏上,单击“SQLCMD 模式”**。

    如果未启用 SQLCMD 模式,则在尝试执行脚本时将出现错误。

  3. 若要同步两个数据库的架构,请通过单击**“Transact-SQL 编辑器”工具栏上的“执行 SQL”**或按 F5 运行此脚本。

    将出现**“连接到数据库”**对话框。

  4. 单击与 EmptyDB 数据库对应的连接,然后单击**“确定”**。

    警告

    如果尝试针对其他数据库运行更新脚本,则可能导致生成意料之外的结果。

    比较不会自动刷新。 如果要再次运行比较以验证是否应用了选定的更新,必须单击**“架构比较”工具栏上的“刷新”**。

后续步骤

现在可以比较两个数据库内的数据。 有关更多信息,请参见如何:比较并同步两个数据库的数据

请参见

任务

如何:比较并同步两个数据库的数据

如何:比较数据库架构

演练:比较两个数据库的数据

演练:比较数据库的架构和数据库项目的架构

概念

将一个或多个表中的数据与引用数据库中的数据进行比较和同步

在 Visual Studio 中创建和管理数据库和数据层应用程序