演练:比较数据库的架构和数据库项目的架构
本主题适用于:
Visual Studio 旗舰版 |
Visual Studio 高级专业版 |
Visual Studio 专业版 |
Visual Studio 学习版 |
---|---|---|---|
在本演练中,通过使用 Visual Studio 将数据库项目的架构与数据库的架构进行比较。根据您的团队使用数据库项目和数据库的方式,您可能需要按一个方向或按其他方向复制架构更改。 团队在数据库开发的整个生命周期内工作的过程中,您可能会遇到以下典型方案:
**项目是源,数据库是目标。**可以使用数据库项目来开发或维护数据库。 在项目的架构中进行更改后,可以将这些更改复制到位于临时服务器上的数据库中。 随后,团队可以将该数据库部署到成品服务器上。
在本演练中执行的比较操作从架构差异生成数据定义语言 (DDL) 脚本。 然后可以使用此脚本将所有或部分数据库项目应用于数据库。 有关更多信息,请参见将更改从项目传播到数据库。
**数据库是源,项目是目标。**可能会在成品数据库的架构中发现错误,或者架构可能过时并需要更新。 此发现可能需要您的团队将紧急更新应用到数据库。 若要使项目与数据库保持同步,您可以将更新导入到数据库项目中。 有关更多信息,请参见如何:将更新从数据库导入数据库项目。
本演练阐释了以下任务:
安装阶段
创建一个数据库项目。 新项目最初为空。
从脚本中导入数据库架构。
配置和生成数据库项目并将其部署到数据库服务器。 数据库和项目具有相同的架构。
生产阶段
向数据库项目中添加表。 添加一个名为 InternationalShippers 表,其中包含三列。
比较这两种架构。 在进行比较时,可以将数据库项目指定为源,将数据库指定为目标。 因此,结果是将 InternationalShippers 表作为一个新表显示在数据库项目中。
将更改从项目传播到数据库。 可以将新的 InternationalShippers 表从数据库项目传播到部署的数据库。 如果按照此过程操作,则将覆盖示例数据库的部分内容。
提示
也可以将更改从数据库传播到数据库项目。 有关更多信息,请参见如何:将更新从数据库导入数据库项目。
系统必备
若要完成本演练,您需要下面的应用程序和权限:
SQL Server 2008
可在目标数据库服务器上创建和更新数据库的权限
Visual Studio 高级专业版或 Visual Studio 旗舰版
安装阶段
创建数据库项目
创建数据库项目
在**“文件”菜单上指向“新建”,再单击“项目”**。
将打开**“新建项目”**对话框。
在**“已安装的模板”下,展开“数据库”节点,然后单击“SQL Server”**。
在模板列表中单击**“SQL Server 2008 数据库项目”**。
在**“名称”中键入“CompareProject”,然后单击“确定”**。
将打开空的 CompareProject 项目,并将其显示在**“解决方案资源管理器”**中。
从脚本中导入数据库架构
创建可从中导入架构的脚本
在**“文件”菜单上指向“新建”,然后单击“文件”**。
此时将打开**“新建文件”**对话框。
在**“类别”列表中,如果尚未突出显示“常规”**,请单击它。
在**“模板”列表中,单击“Sql 文件”,然后单击“打开”**。
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
在**“文件”菜单上,单击“将 SqlQuery_1.sql 另存为”**。
**“另存文件为”**对话框打开。
在**“对象名”**中,键入 SampleImportScript.sql。
可以将文件保存到计算机中的任何位置。 记下该位置,因为在下面的步骤中必须使用它。
单击**“保存”**。
在**“文件”菜单上,单击“关闭解决方案”**。
接下来,创建一个数据库项目,并从已创建的脚本导入架构。
从脚本中导入数据库
在**“项目”菜单上,单击“导入数据库脚本”**。
阅读“欢迎”页之后,单击**“下一步”**。
单击**“浏览”**,浏览至保存 SampleImportScript.sql 文件的位置。
双击 SampleImportScript.sql 文件,然后单击**“完成”**。
将导入脚本,在该脚本中定义的对象添加到数据库项目中。
查看摘要,然后单击**“完成”**。
配置、生成和部署数据库项目
这些过程将创建一个在独立开发环境(或沙盒)中具有导入的架构的数据库,您可以在该环境中开发和测试数据库。
配置和生成数据库项目
在**“解决方案资源管理器”**中,单击 CompareProject 项目。
在**“项目”菜单上,单击“CompareProject 属性”**。
此时将显示 CompareProject 项目的属性。
单击**“部署”**选项卡。
在**“部署操作”列表中,单击“创建部署脚本(.sql)并部署到数据库”**。
在**“目标数据库设置”中,单击“编辑”**。
在**“连接属性”对话框中,设置要使用的数据库的连接属性,然后单击“确定”**。
**“目标连接”**框将显示正确的连接字符串。
警告
应在测试服务器、开发服务器或本地计算机上创建数据库。 不应使用生产服务器。
在**“目标数据库名称”**框中键入“CompareProjectDB”。
在**“文件”菜单上,单击“全部保存”**。
在**“生成”菜单上,单击“生成解决方案”**。
即会基于刚刚设置的项目属性生成部署脚本。 生成状态显示在**“输出”窗口中,并且最后一行显示为“生成: 成功或最新 1 个”**。
部署数据库项目
在**“解决方案资源管理器”**中,单击 CompareProject 项目。
在**“生成”菜单上,单击“部署 CompareProject”**。
或者,也可以在**“解决方案资源管理器”中右击项目,然后单击“部署”**。
警告
应对测试服务器、开发服务器或本地计算机运行此部署。 不应使用生产服务器。
数据库项目部署到新数据库。 部署状态显示在**“输出”窗口中,并且最后一行显示为“部署已成功”**。
生产阶段
向数据库项目中添加表
向项目中添加表
在**“视图”菜单上,单击“数据库架构视图”**。
**“架构视图”**将打开并显示 CompareProject 项目的架构。
在**“架构视图”**中,展开“CompareProject”节点,再展开“架构”节点。
右击**“Sales”,指向“添加”,然后单击“表”**。
**“添加新项 - CompareProject”**对话框将打开。
在**“模板”下,单击“表”**。
在**“名称”中键入“InternationalShippers”,然后单击“添加”**。
一个名为 InternationalShippers 的表将会添加到 CompareProject 项目中。 相应的表定义将显示在 Transact-SQL 编辑器中。
将 InternationalShippers.table.sql 中的 SQL 脚本更改为以下语句:
CREATE TABLE [Sales].[InternationalShippers] ( [ShipperID] [int] NOT NULL IDENTITY(1,1), [CompanyName] [nvarchar] (40) NOT NULL, [Region] [nvarchar] (40) NOT NULL, [Phone] [nvarchar] (24) NULL ) ON [PRIMARY]
单击**“保存 InternationalShippers.table.sql”**。
在**“架构视图”中右击 InternationalShippers 表,然后单击“在解决方案资源管理器中查看文件”**。
InternationalShippers.sql 文件将在**“解决方案资源管理器”**中突出显示。
按 F4。
“属性”窗口将出现并显示 InternationalShippers.table.sql 文件的属性。 Build Action 属性设置为“生成”,用于指示该文件包含数据库对象的定义,应对该文件进行分析和验证。
比较这两种架构
比较这两种架构
在**“数据”菜单上,指向“架构比较”,然后单击“新建架构比较”**。
将打开**“新建架构比较”**对话框。
在**“目标架构”中单击“数据库”,并指定与本演练前面部署的数据库的连接,然后单击“确定”**。
该数据库的架构将与已更改项目的架构进行比较,结果显示在**“架构比较”**窗口中。 在 CompareProject 列中将显示 [Sales].[InternationalShippers] 表。 表的状态为“新建”,其更新操作为“创建”。 如果您现在传播更改,则将在目标数据库中创建该表。 有关更多信息,请参见以下过程。
检查并忽略预期的差异
在比较结果的列表中,滚动到**“SQL 文件”**节点。
对于目标数据库,列表中将显示状态为**“缺少”**的两行:一行代表文件组文件,一行代表日志文件。
单击每行的**“更新操作”列以将操作更改为“跳过”**。
当更新数据库架构时,您通常不希望更改与目标数据库关联的文件组文件或日志文件。 通过将操作更改为“跳过”,目标数据库将继续使用其当前文件。
接下来,您可以选择更新目标数据库以匹配源数据库。
将更改从项目传播到数据库
将更改传播到目标数据库
在**“架构比较”窗口中,单击“写入更新”**。
提示
如果项目包含一个或多个错误,则可能会禁用“写入更新”按钮。 如果发生这种情况,则“架构比较”状态栏中将显示一条消息。
将执行**“架构比较”**窗口中列出的操作,包括针对 InternationalShippers 表的“创建”操作。 此同步可以更改数据库的架构,使其与数据库项目的架构匹配。 在更新操作完成后,将重新比较架构,并刷新结果。
在更新目标架构的过程中,通过打开**“数据”菜单,指向“架构比较”并单击“停止写入目标”**,可以取消更新操作。
警告
由于某些架构更改无法在一个事务范围内执行,因此如果取消更新操作,可能会丢失数据。 例如,目标数据库中的表在准备重新创建过程中可能会被删除。 如果此时取消更新,则可能会丢失该表。 如果发生此类数据丢失,您应重新比较架构。