使用 Visual Studio 2010 数据库项目填充静态数据的最佳实践?

Posted

技术标签:

【中文标题】使用 Visual Studio 2010 数据库项目填充静态数据的最佳实践?【英文标题】:Best practice to populate static data using a Visual Studio 2010 database project? 【发布时间】:2011-05-15 20:38:28 【问题描述】:

您如何使用 Visual Studio 数据库项目向您的数据库填充静态的、源代码控制的数据?我已经尝试了以下所有三种策略,发现每一种都比上一种更好。我正在使用但对策略 3 不完全满意。您还有其他选择吗?

    将插入脚本放在“数据生成计划”文件夹中。引用“Script.PostDeployment.sql”文件中的脚本,将它们包含在部署过程中。

    -- 优点:直截了当 -- 缺点:slooooooow -- 缺点:后续部署必须先删除静态数据或检查数据不存在=>效率低

    第一次使用最方便的方法将数据插入数据库(例如,可以是 SSMS 编辑表功能)。使用 bcp 命令行实用程序提取该数据以创建一堆数据文件并将它们添加到您的项目中。创建在“Scripts.PostDeployment.sql”文件中引用的脚本,该脚本为每个数据文件执行“批量插入”语句。

    -- 优点:比插入语句快得多 -- 优点:可以利用 SSMS 编辑表功能 -- 缺点:每个批量插入语句都需要数据文件的完全限定文件名,因此如果数据文件位于我的机器上的“C:\Projects\Dev\Source\foo.dat”,那么远程开发机器也必须将它们放在该位置,否则批量插入语句将失败 -- 缺点:在后续部署中执行批量插入语句之前必须删除现有的静态数据

    在部署期间创建临时表来保存静态数据,并使用 sql 合并语句将这些表与目标表同步。请参阅 either 的 these 博客文章。

    -- 优点:似乎 sql merge 对问题有完美的语义 -- 缺点:此策略的逻辑在每个文件中重复 -- 缺点:表定义在 sql 合并文件中作为临时表重复

有没有更好的替代策略?我放弃了策略 1,因为它太慢了。由于完全限定的文件名问题,我不喜欢策略 2。我对策略 3 感到满意,但并不激动。有最佳做法吗?

【问题讨论】:

您是否可以选择将数据保留在目标数据库中,而不是每次都重新填充? @David:我不相信有任何这样的选择,除非有人可以告诉我。它需要以某种方式成为脚本解决方案的一部分。策略 3 使用 merge 命令处理此问题。必须修改策略 1 以在插入之前首先检查数据是否存在。策略 2 也是如此。 这可能对您没有什么安慰,但我们刚刚发布了 SQL Source Control 2,它具有静态数据支持。可悲的是,这不支持数据库项目——至少现在还不支持。但是,我们正在认真考虑这一点。如果你有兴趣,请在这里投票:redgate.uservoice.com/forums/39019-sql-source-control/… 对于策略 1,slooooooow 是轻描淡写的。我目前正在进行一个绿地项目。刚开始在数据库创建和默认数据中运行。我转向 DB 项目是为了寻找一种更好的方式来维护 DB 的东西,但现在我觉得手动运行脚本更容易,纯粹是因为它部署起来太慢了,而且正如你所说,如果你必须首先手动检查是否存在您想在部署后脚本中运行数据并使其具有幂等性。 【参考方案1】:

我们尚未将 VS 2010 数据库项目投入生产,但对于我们的内部项目,我们将生产数据库加载到目标数据库并在开发/测试阶段构建/部署到它。也就是说,我知道如果您有多个 prod 数据库和发送到每个数据库的静态数据,Tim 可能对您不起作用。但是,它可以用于像我们这样的单一产品数据库商店。

【讨论】:

感谢您的回复。你介意给我详细一点吗?那么您是否备份产品,将其还原到目标(因此目标具有所有数据),然后从 VS 运行部署以同步模式?如果这是真的,那么您似乎无法阻止某人向 prod 添加数据,然后这些数据将传播到目标。我正在寻找一种源代码控制的方式来表达:“这是我们的基线数据,在我单击部署后,我确信它存在于目标上。”由此推论,同样的方法也将支持:“这是一个构成可重复部署的测试用例的数据集合”【参考方案2】:

在您的 insert.sql 脚本中,您可以在 [__RefactorLog] 表(部署使用的系统表)中放置一个 GUID,并在插入数据之前检查此 GUID 是否存在:

:setvar SOMEID "784B2FC9-2B1E-5798-8478-24EE856E62AE" //在VS2010中用Tools\CreateGuid创建guid

如果不存在(SELECT [OperationKey] FROM [dbo].[__RefactorLog] where [OperationKey] = '$(SOMEID )')

开始

...

INSERT INTO [dbo].[__RefactorLog] ([OperationKey] ) values( '$(SOMEID )' )

结束

然后,只有在不存在或需要时才插入数据(通过更改 Guid)。

【讨论】:

【参考方案3】:

您可以使用数据库项目的模式输出来更新目标数据库 有一个cmd工具可以在其他机器上运行,看你vs2010 IDE没有

所以你的数据仍然是一样的,除非你在任何一列都有下降

【讨论】:

【参考方案4】:

这就是我解决这个问题的方法,以防其他人发现这很有用......

策略是在构建数据库项目之前设置一个 sqlcmdvars 变量。此变量将包含可以从部署后脚本引用的构建文件夹的绝对路径。然后,在部署脚本中将它用于您可能需要的任何其他文件或资源将是一件简单的事情。这种策略的优点是所有路径都是相对于项目文件的,而不需要硬编码的共享路径。

创建一个新的 Sql 命令变量名称 $(MSBuildProjectDirectory)。这将在预构建脚本中被覆盖。

创建一个 msbuild 脚本来设置 sql 命令变量并构建数据库。

<Project ToolsVersion="4.0" DefaultTargets="BuildDatabase"  xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<PropertyGroup>
    <DatabaseServer>(Local)</DatabaseServer>
    <DeploymentConnectionString>Data Source=$(DatabaseServer)%3BIntegrated Security=True%3BPooling=False</DeploymentConnectionString>
    <Configuration>Release</Configuration>
</PropertyGroup>
<Target Name="BuildDatabase">
    <!-- Sets the projet path variable so that the post deployment script can determine the location of the bulk insert csv files. -->
    <XmlUpdate
        Prefix="urn"
        Namespace="urn:Microsoft.VisualStudio.Data.Schema.Package.SqlCmdVars"
        XmlFileName="$(MSBuildProjectDirectory)\DatabaseProjectName\Properties\Database.sqlcmdvars"
        XPath="/urn:SqlCommandVariables/urn:Properties/urn:Property[urn:PropertyName='MSBuildProjectDirectory']/urn:PropertyValue"
        Value="$(MSBuildProjectDirectory)\DatabaseProjectName" />

    <MSBuild
            Projects="DatabaseProjectName\DatabaseProjectName.dbproj"
            Properties="Configuration=$(Configuration);
                    TargetDatabase=DatabaseName;
                    TargetConnectionString=$(DeploymentConnectionString);
                    GenerateDropsIfNotInProject=True;
                    BlockIncrementalDeploymentIfDataLoss=False;
                    DeployToDatabase=True;
                    IgnorePermissions=True"
            Targets="Build;Deploy">
        <Output TaskParameter="TargetOutputs" ItemName="SqlFiles"/>
    </MSBuild>
</Target>

如下更新您的部署后脚本...

BULK INSERT [dbo].[TableName] FROM '$(MSBuildProjectDirectory)\Scripts\Post-Deployment\Data\YourDataFile.csv'
WITH (FIELDTERMINATOR = ',', ROWTERMINATOR='\n')

【讨论】:

以上是关于使用 Visual Studio 2010 数据库项目填充静态数据的最佳实践?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Visual Studio 2010 C# 的数据透视表

如何在 Visual Studio 2010 中使用 Visual Studio 2008 创建的 DLL?

从 Visual Studio 2008 升级到 Visual Studio 2010 速成版

如何让 Visual Studio 2015 使用 Access 2010 LIKE 通配符

使用 Visual Studio 2010 数据库项目填充静态数据的最佳实践?

visual studio 2010怎么查看函数