简体   繁体   English

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

[英]Best practice to populate static data using a Visual Studio 2010 database project?

How do you populate your database with static, source-controlled data using a Visual Studio database project? 如何使用Visual Studio数据库项目使用静态的源控制数据填充数据库? I have tried all three strategies below, finding each one to be progressively better than the last. 我已经尝试了以下所有三种策略,发现每一种策略都比上一次更好。 I am using but not completely satisfied with strategy 3. Do you have an another alternative? 我使用但不完全满意策略3.你有另一种选择吗?

  1. Place insert scripts in the "Data Generation Plans" folder. 将插入脚本放在“数据生成计划”文件夹中。 Reference the scripts in the "Script.PostDeployment.sql" file to include them in the deployment process. 引用“Script.PostDeployment.sql”文件中的脚本以将其包含在部署过程中。

    -- advantage: straight-forward - 优势:直截了当
    -- drawback: slooooooow - 缺点:slooooooow
    -- drawback: subsequent deploys must first delete static data or check for non-existence of data => inefficient - 缺点:后续部署必须首先删除静态数据或检查数据是否存在=>效率低下

  2. Insert the data into the database the first time using whatever method is most convenient (eg could be the SSMS edit table feature). 使用最方便的方法(例如,可能是SSMS编辑表功能)第一次将数据插入数据库。 Extract that data using the bcp command line utility to create a bunch of data files and add them to your project. 使用bcp命令行实用程序提取该数据,以创建一堆数据文件并将其添加到项目中。 Create a script referenced in the "Scripts.PostDeployment.sql" file that executes a "bulk insert" statement for each data file. 创建“Scripts.PostDeployment.sql”文件中引用的脚本,该脚本为每个数据文件执行“批量插入”语句。

    -- advantage: much faster than insert statements - 优点:比插入语句快得多
    -- advantage: can leverage SSMS edit table feature - 优点:可以利用SSMS编辑表功能
    -- drawback: each bulk insert statement requires a fully qualified file name to the data file so if the data files are located on my machine at "C:\\Projects\\Dev\\Source\\foo.dat" then the remote dev machine must also have them at that location or the bulk insert statement fails - 缺点:每个批量插入语句都需要数据文件的完全限定文件名,因此如果数据文件位于我的机器上“C:\\ Projects \\ Dev \\ Source \\ foo.dat”,那么远程开发机器也必须将它们放在该位置或批量插入语句失败
    -- drawback: must delete existing static data before executing bulk insert statements on subsequent deploys - 缺点:必须在后续部署中执行批量插入语句之前删除现有静态数据

  3. Create temporary tables during deployment to hold the static data and use the sql merge statement to synchronize these tables with the target tables. 在部署期间创建临时表以保存静态数据,并使用sql merge语句将这些表与目标表同步。 See either of these blog posts. 查看这些博文中的任何一篇。

    -- advantage: seems like sql merge has the perfect semantics for the problem - 优点:似乎sql merge对问题有完美的语义
    -- drawback: the logic for this strategy is repeated in each file -- drawback: table definitions are repeated as temporary tables in the sql merge files - 缺点:在每个文件中重复此策略的逻辑 - 缺点:表定义作为sql合并文件中的临时表重复

Is there a superior alternative strategy? 是否有更优越的替代战略? I gave up on strategy 1 because it was too slow. 我放弃了策略1,因为它太慢了。 I dislike strategy 2 due to the fully qualified file name issue. 由于完全限定的文件名问题,我不喜欢策略2。 I am satisfied but not thrilled by strategy 3. Is there a best practice? 我对战略3感到满意但并不激动。是否有最好的做法?

In your insert.sql script, you can put a GUID in the [__RefactorLog] table (which is a system table used by deployment) and check if this GUID exist before inserting your data like this : 在您的insert.sql脚本中,您可以在[__RefactorLog]表(这是部署使用的系统表)中放置一个GUID,并在插入数据之前检查此GUID是否存在,如下所示:

:setvar SOMEID "784B2FC9-2B1E-5798-8478-24EE856E62AE" //create guid with Tools\\CreateGuid in VS2010 :setvar SOMEID“784B2FC9-2B1E-5798-8478-24EE856E62AE”//使用VS2010中的Tools \\ CreateGuid创建guid

IF NOT EXISTS (SELECT [OperationKey] FROM [dbo].[__RefactorLog] where [OperationKey] = '$(SOMEID )') 如果不是EXISTS(SELECT [OperationKey] FROM [dbo]。[__ RefactorLog],其中[OperationKey] ='$(SOMEID)')

BEGIN 开始

... ...

INSERT INTO [dbo].[__RefactorLog] ([OperationKey] ) values( '$(SOMEID )' ) INSERT INTO [dbo]。[__ RefactorLog]([OperationKey])值('$(SOMEID)')

END 结束

Then you insert data only if not exist or if you want to (by changing the Guid). 然后,只有在不存在或者您想要的情况下(通过更改Guid)才插入数据。

This is how I solved this problem in case anyone else finds this useful... 这是我解决这个问题的方法,以防其他人发现这个有用......

The strategy is to set a sqlcmdvars variable before building the database project. 策略是在构建数据库项目之前设置sqlcmdvars变量。 This variable would contain the absolute path to the build folder that can be referenced from the post deployment script. 此变量将包含可从后部署脚本引用的构建文件夹的绝对路径。 Then it would be a simple matter to use that in the deployment script for any additional files or resources that you might need. 然后,在部署脚本中使用它可能需要的任何其他文件或资源都是一件简单的事情。 The advantage of this strategy is that all the paths are relative to the project file instead of requiring a hard coded shared path. 此策略的优点是所有路径都相对于项目文件,而不需要硬编码的共享路径。

Create a new Sql command variable name $(MSBuildProjectDirectory). 创建一个新的Sql命令变量名$(MSBuildProjectDirectory)。 This will get overriden in the prebuild script. 这将在prebuild脚本中被覆盖。

Create an msbuild script that would set the sql command variable and build the database. 创建一个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>

Update your post deployment script as follows... 更新您的部署后脚本,如下所示...

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

You can use the schema output from the database project to update the target database There is a cmd tool to run it on other machine is not with in view of you vs2010 IDE 您可以使用数据库项目中的架构输出来更新目标数据库有一个cmd工具可以在其他机器上运行它而不是为了您的vs2010 IDE

So you data will still be the same, unless you have drops on any column 所以你的数据仍然是相同的,除非你有任何列的下降

We haven't rolled our VS 2010 db project into Production yet, but for our in-house project we load the production database into the target database and build/deploy to it during the dev/test phase. 我们还没有将我们的VS 2010 db项目推广到Production,但是对于我们的内部项目,我们将生产数据库加载到目标数据库,并在开发/测试阶段构建/部署到它。 That said, I understand that probably will not work for you Tim if you have multiple prod databases and static data that goes out to each. 也就是说,我明白如果你有多个prod数据库和静态数据,那么对你来说可能不会有用。 But, it can be done for single prod db shops like ours. 但是,它可以用于像我们这样的单个产品分销商店。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM