SSDT: Tips, Tricks, and Gotchas

I wanted to add a short post to make sure I highlight some things that will trip people up or otherwise cause issues.

 

  • When setting trigger order for triggers on a table, you could run into an issue with Publishing your database. The project will build successfully, but throw a “Parameter cannot be null” error for parameter “Key”. This is an internal bug with the product as of at least SQL 2012 CU2. It’s been entered as an internal bug within MS with a workaround. To workaround the issue, do not try to set the trigger order in the table definition, but rather put this code in a post-deploy script.
    • This is supposed to be fixed in a future release of SSDT so your experience may vary.
  • Importing encrypted objects may fail. If you want to store encrypted objects in your project, you’ll likely need the code in order to create them in the project.
  • Unlike the Schema Compare option in VS 2010, there is no way to set the default Schema Compare options nor a way to filter out “skipped” objects in the schema compare.
    • I’d love some ideas on how better to handle this. You may be able to save the compare within the project for future re-use, but I had little success with this in VS 2010 Projects so have been reluctant to try that route again.
  • If your database uses FILESTREAM, you will not be able to debug using the default user instance that SSDT provides. You will need to point your debugging instance to a SQL Server install that supports FILESTREAM. See this forum post for more details.
    • Set this in the Project Properties and point to an actual instance of SQL Server that supports the feature(s) you want to use.
  • SQL Projects will substitute CONVERT for CAST in computed columns at the time of this writing. They also push default constraints with extra parentheses around the default value. If you clean these up from the target server, be aware that on your next Publish action, you could end up with extra work being done to make your target database use those parentheses or the CONVERT function.
    • To work around this, do a SQL Schema compare after a release to find any areas where the schema on the server differs from that in the project. For instance you may see a DEFAULT (getdate()) in your server, but have DEFAULT getdate() in your project.  Add the parentheses to your project to avoid unnecessary changes.

 

Do you have any tips to share? Add them to the comments below.

Advertisements

SSDT: SQL Project Snapshots

SSDT allows for snapshots to be taken of the project at any point. Just right-click the project name and select the option to “Snapshot Project”.

clip_image001

This builds a dacpac file into a folder within the project called “Snapshots” with a default name format of Projectname_yyyymmdd_hh-mi-ss.dacpac.
This file contains a build of the project at the time the snapshot was taken, including all objects and scripts.
 
Uses (by no means a complete list)

  • Save a specific version of your project to use for release
  • Save this version of the project before making changes to the underlying project
  • Use as a source for schema compare
  • See the differences between snapshots and/or the current project through schema compare
  • Baseline your project
  • Roll back to this state
    • Schema Compare with the snapshot as the source and the Project as the target
    • Import into a new project with this as the source.
    • Import into current project, but be aware that this could easily produce a lot of duplicates

SSDT: Publishing Your Project

Build the project

In order to successfully publish your project, it must first be able to build successfully.

Start by building your project. Right-click the project and select “Build”.

clip_image001

If the build is successful, the project can be published.

 

You may want to create a folder within your project to store saved Publish Profiles. These can be used later to easily publish the project to your servers.

clip_image002

 

Creating Publish Profiles

Right-click the project and select Publish. This will bring up the Publish Database dialog.

  • Choosing to publish or opening a saved publish profile will initiate a build of the project.

clip_image003

Choose your target database, set your advanced options (similar to Schema Compare options), and choose the “Save Profile As” option to save this to a location within your project. Selecting the “Add profile to project” option will create the publish profile in the root of the project. You may wish to either move the file to a folder storing all of your publish profiles or, if you saved it without adding to the project, show all files of the project so you can include the file in the project.

clip_image004

 

Some options you may want to consider:

  • “Always re-create database” – this will re-create the database. Any data in the database will be lost.
  • “Block incremental deployment if data loss might occur” – If there are any changes that could result in the publish action failing because of data loss, this option will stop the script from running.
  • “DROP objects in target but not in project” – This will remove anything in the database that doesn’t exist in the project. Useful if you want consistency, but you may want to ensure this isn’t checked if there could be objects in the database that were created, but didn’t make it to the project.

Under the “Advanced Deployment Options”

  • Allow Incompatible Platform – Useful if you may publish to a different version of SQL Server than the one specified in the project
  • Include transactional scripts – Will run the entire update operation as a transaction. If any one part fails, the transaction will roll back. If you have cross-database dependencies, selecting this option could result in no changes being published if you’re publishing to a new server. For a new publication, you may want to de-select this option to ensure a successful deploy of what can be published.
  • Script state checks – This option will ensure that the publish action will only work on the specified server and database.
  • Verify deployment – Checks the database and project before publishing to try to ensure there are no changes that will cause problems with the publication such as missing data for a foreign key.

 

Using Publish Profiles

Once you’ve set up your publish profiles, you can easily use these to push changes to that server and database without needing to specify additional parameters. The easiest way to use them is to double-click the Publish Profile within the project and choose to either “Generate Script” or “Publish”.

Generate Script will generate a script for you to use to update the target at a later time (run in SQLCMD mode).

Publish will immediately attempt to push the changes to the target.

You can also use these at a later point to push changes through the SQLPackage.exe command line.

 

SQLPackage

To publish your package through a command line we use something like the following:

Code Snippet
  1. sqlpackage /a:publish /sf:.\sql\Local\Adventureworks2008.dacpac /pr:.\Publish\Local.publish.xml

The above will:

  • Use the “Publish” Action
  • Use the Source File named Adventureworks2008.dacpac, built in the sql\Local folder
  • Use the publish profile named “Local.publish.xml” (defined to push to the local SQL Server)

You may want to add SQLPackage.exe to your path. By default it is installed in:

C:\Program Files (x86)\Microsoft SQL Server\110\DAC\bin

You can override quite a few of the default settings through various command line arguments. This includes source, target, and variables. You can find a full list of the command line arguments at the SQL Package reference online.

 

Jenkins Automation for CI

We use Jenkins at my current workplace and set up a Jenkins job to do the following (With thanks to Matthew Sneeden for the assistance.):

  • Get the latest from our mainline repository
  • Build each SQLProj file.
    • Building the SLN file will result in also attempting to publish the database
    • msbuild .\Adventureworks.sqlproj /t:build /p:Configuration=”Local”
      • This assumes that msbuild.exe is in your path.
    • Configuration is mostly to control the location of the dacpac file generated.
  • Run SQLPackage w/ a specified Publish Profile for the appropriate environment and using the newly built dacpac as the source.

We are currently investigating how we can use Snapshot files to better control releases to our UAT and Production environments. This series will be updated when that information is available.

SSDT: Errors and Warnings

SSDT includes an Errors and Warnings window that is well worth your attention. Ideally, your project should have no errors or warnings.

clip_image001

 

However, sometimes coding errors slip in to your project or you get warnings that an object can’t be found because it exists in another database. Sometimes a warning might appear because an object is missing completely, in this project or another one. In these cases, it’s well worth checking this section to find out where you may have some issues.

Warnings are not necessarily a problem. SSDT will bring possible issues to your attention, but warnings will not stop a project from building and publishing unless you have set the option to treat warnings as errors or unless there really is an underlying problem that causes an issue during the publish phase.

For example, if I modify the Person.Address table to add a new column in the code, but forget to add a comma, I’ll get an error something like this.

clip_image002

If you double-click on the line, the editor should open the appropriate file and take you pretty close to your problematic line. Correct the problem, save the file, and move on to the next error.

 

Some common warnings/errors

  • 4151 – Unresolved database reference. This is often caused when one of the objects in a database references another. This can often be resolved by creating a database reference.
  • 71562 – Unresolved database reference warning.
  • 71502 – Another unresolved database reference warning.

How to globally suppress certain warnings

  • Right click the root of the project and select properties
  • Click on the “Build” tab
  • Enter in the numeric portion of the codes, separated by commas. Remove the “SQL” and any leading zeroes when entering the code.

clip_image003

SSDT: Updating a Project Manually

Sometimes it’s necessary to modify the project manually. The change might require specific tweaking to include just a couple of new lines in a stored procedure or function. It might be just adding a column to a table. Maybe you know exactly what change needs to be made and would rather just edit it manually instead of comparing or importing. Whatever the reason, updating your project manually can be done without too much trouble.
If you know the name and location of the file you want to edit, just go straight to it and right-click it.
clip_image001
You have two ways to edit the file – using “View Code” will bring up a T-SQL script. Edit as you would any other T-SQL script and save. Remember that SSDT scripts create all base objects using CREATE scripts.
If you choose to View Designer, you’ll see a new screen combining a design view with a T-SQL editor.
clip_image002
 
Here you can choose to edit within either window. The code will be kept in sync across the panels. You can right-click any of the Keys, Indexes, Triggers, Constraints in the upper window and choose to add a new one. You’ll get a shell of the script to create a new object tied to this table. Modify its code to match what you want to do and save the file.

  • This is different behavior from the older Database Projects. Those would create separate files for each object by default. In SSDT, the scripts are all put together in one script unless you upgraded from a DB Project.
  • The only place SSDT supports “GO” to break up the batches is within these create scripts. You cannot use GO in a post or pre deploy script.
  • If you highlight a column in the table, you can give it a description in the Properties window. This is an easy way to propagate object/column descriptions into your SQL Server.
  • You can select the table’s properties in the Properties window dropdown to edit its properties/description.

clip_image003
 
 
SQL Server Object Explorer
If you hit the F5 key inside of a project to debug the project, SSDT will build a local database, often hosted in an instance called (localdb)\Databasename. This will run the database project in a debug session. If you then open the SQL Server Object Explorer view, you can edit the project and underlying scripts.

This works in most instances where you’re using basic SQL Server functionality. If you’re using any more advanced features such as Filestream, you’ll want to change the location for this debug instance. You can change these in the project properties.

clip_image004

Double-clicking the HumanResources.EmployeePayHistory table above brings up the editor for the underlying table in the project.
clip_image005

SSDT: Updating a Project by Importing Scripts

Sometimes your developers will work on new SQL Objects and give you scripts to alter or create objects. SQL Projects support importing those scripts into your project. Start by choosing the Import Script option.

clip_image001

Find your script or scripts.

clip_image002

Select your options for import:

clip_image003

 
If you see the following text in your log, be sure to check this file to see if something was missed on import. You’ll need to manually make these changes, if applicable. In a lot of cases, the statements not understood tend to be “GO” statements.

“In the script that you provided to the import operation, one or more statements were not fully understood. These statements were moved to the ScriptsIgnoredOnImport.sql file. Review the file contents for additional information.”

I’ve also found that “ALTER TABLE” statements are not well understood by SSDT within the imported scripts. If you get several scripts that include these and aren’t understood, you can either compare the physical database to the project or manually update the project. (This has been acknowledged by Microsoft as “working as designed” even if we might wish that this could actually change the script for the object instead.)

SSDT: Updating by Using Schema Compare

Sometimes changes are made to a shared database that need to be brought into your SQL Project and there are no saved change scripts for those changes. Other times you may just want to see what will change when you publish a project. SSDT has included a Schema Compare option for SQL Projects, dacpac files, and databases.
If you are using VS2010, there are two options for SQL and Data.
clip_image001

  • The “Data” menu is used for the older DB Projects within VS2010. There’s a useful data compare option in there, but the schema compare will not work for SQL 2012 or SQL Projects.
  • The “SQL” menu contains the Schema Compare item with a sub-item to do a new Schema Comparison

clip_image002

To update your project from a shared database, start a “New Schema Comparison”. You’ll see a screen something like this:

clip_image003

Setting your source/target is pretty straightforward and each will produce a screen something like the following:

clip_image004

You can choose to compare against an open project, a live database, or a Data-tier Application File (dacpac). In our case, we are going to select a live database as the source and our project as the target.
Once selected, you may want to change the options to exclude certain object types or ignore certain settings such as file placement. Unlike in VS2010, the options cannot be set to some default at this time. When you’ve set the options to your liking, click the “Compare” button.

clip_image005

If there are any differences, you’ll see a list of them here. The comparison window shows where there are differences between the source and target. This can be really helpful to know whether or not to include this change in the update.
To exclude a change, clear the checkbox next to it in the upper section of the window. A green + indicates that this object will be created. A red – indicates that the object will be dropped. The blue pencil indicates that the object will be modified. At this time there is no way to hide any unchecked items that show in the compare.
Once you’re satisfied with your selection, click the “Update” button to push those changes into your project.

SSDT: Pre and Post Deploy Scripts

At some point, you will likely need to release changes that contain more than just schema changes. You may need to update data in a table, remove data that could cause a problem, or insert some data to support a code release. To support these changes, SSDT provides support for Pre-Deploy and Post-Deploy scripts.
These scripts are not created by default in a new SSDT project. To organize your scripts, you may want to create a folder structure similar to the following.
clip_image001
If you right-click the Post or Pre Deploy folders, you can choose to add a Script item.
clip_image002
You will then get a choice of which type of script to include. Choose Pre or Post deployment, as appropriate, and name the file accordingly.

You can only have one Pre-Deployment script and one Post-Deployment script per project as part of the Build! All included scripts must be set to “Not in build” or you will likely have errors.

clip_image003
If you look at the properties of these scripts, you will see that the Build Action is set to PreDeploy or PostDeploy. Opening the Post-Deploy script will show this default text.

/*
Post-Deployment Script Template
--------------------------------------------------------------------------------------  This file contains SQL statements that will be appended to the build script.  Use SQLCMD syntax to include a file in the post-deployment script.  Example:      :r .\myfile.sql  Use SQLCMD syntax to reference a variable in the post-deployment script.  Example:      :setvar TableName MyTable                SELECT * FROM [$(TableName)]
--------------------------------------------------------------------------------------
*/

 
Using Pre and Post Deploy Scripts
These files are interpreted as SQLCMD scripts by SSDT. You can use most valid SQLCMD syntax within the script file to include other scripts and set variables. At the time of this writing, you cannot use the :ON ERROR IGNORE command within a script. This will hopefully be addressed in a future release of SSDT.
Pre-Deploy scripts will always run before the schema changes are run. If you alter the database in a way that changes the schema, you may encounter errors with the release. E.g., if you make schema changes to the Person.Person table, but drop that table in a Pre-Deploy script, your publish action will likely fail.
Likewise, Post-Deploy scripts will always run after the publish action. This makes them a great place to insert new data, make small adjustments to the system, or perhaps implement custom security and permissions. The caveat to using post-deploy scripts to make changes is that the changes need to be repeatable. If you write an insert statement for a new lookup value, that same insert will run next time unless you check for the existing value first.
To create a new script to run in pre or post deploy:

  • Right-click the appropriate folder (Pre-Deploy, Post-Deploy, other)
  • Choose to add a “script” and select the “Script (Not in build)” option
  • Give it a name, preferably one without spaces as it will make it easier to run the pre or post deploy script.
  • Add your code changes. You may want to give it some descriptive comments and sometimes a Print statement can be helpful if you want to see progress as you run a deploy script manually.

    • Make sure that you can re-run this script without causing errors! Check for data that may already exist, use outer joins, wrap your code in Try/Catch – whatever you need to do to make sure that you can have this run again if necessary.
  • After saving the script, edit your pre or post-deploy script and add a new line in a non-commented area something like:

Run a script called “MyScript”

  1. :r .\MyScript.sql

    • This assumes that your script is in the same folder as your pre or post-deploy scripts. Adjust the relative paths as needed for the script you created.

  • Save your deploy script.

The next time you publish your project, it will pick up this script and include it in your change set. If you choose to create a script on publish, you can see the full text of your scripts included in the pre or post-deploy section of your change script.
 
Cleanup of Pre and Post Deploy Scripts
There are several options for cleanup, but one of the best suggestions I’ve seen has been to generate project snapshots and then remove the script references from your pre/post deploy scripts and the script files themselves from the project. They will still be saved in the snapshot, but will not be in your project anymore.  You may be able to manage this well through your Version Control System, but snapshots do have some advantages.
Pros:

  • Your project will remain somewhat clean.
  • Script files will be saved with their appropriate snapshot, ideally tied to a particular release.
  • Less concern about whether a script is replayed because it’s removed.
  • Good for scripts that have a larger impact and should only be run one-time.

Cons:

  • It’s a manual process and requires some attention to detail.
  • You need to look in the snapshots to see what scripts were used.
  • It may require that you have a more formalized release process.
  • You may need to publish several snapshots to bring the database up to a current version.

SSDT: External Database References

If your database references other databases, you’ll need a *.dacpac file for each external database referenced in your code. For example, if you reference AdventureWorksDW2008 from Adventureworks2008, you’ll need to add that as a database reference.
 
To add a Database Reference to your project

  • Right-click the “References” folder in your project or choose the “Project” menu and select the option to “Add Database Reference”

clip_image001

  • Browse for your dacpac file
  • Choose the appropriate database location. (Same, Different DB / Same Server, or Different DB / Different Server)
  • If your database name doesn’t change, clear out the “Database Variable” column. It isn’t immediately obvious, but doing this will let you keep referencing your database in the same manner you do currently.
    • If this database name can vary, populate the Database Variable field. You’ll need to replace this reference in your code with the variable from this column.
    • If you’re referencing a database on a linked server, this would probably be better served with a static database name and a “Server Variable”. Make sure that server variable is set appropriately when you publish the database.
    • This should be addressed with a future release of SSDT.
  • You may choose to suppress errors if there are unresolved references in the project. This is useful if your dacpac file could be out of date. You can still code against an object you know to exist, but isn’t in the reference file yet.
  • If you use Linked Servers, you’ll probably want to use the Server Variable to ensure that you can release your code in different environments.

clip_image002

 
Some Best Practices and Lessons Learned

  • Make a shared folder to store your dacpac files in a common place. This should be easily accessible from all of your SQL Projects.
    • If you use C:\DatabaseProjects as your base for all SQL Server projects, create a folder in there to store your shared dacpac files.
  • Because all paths are relative to the project, you may need to copy the master/msdb dacpac files that ship with SSDT into your shared folder. You can find these files in your Visual Studio folder in a path similar to the following.

Drive:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Microsoft\SQLDB\Extensions\SqlServer\VersionNumber\SqlSchemas

    • If you support multiple SQL Server editions, you may want to rename master/msdb files with their user-friendly version number. E.g., the master.dacpac file in your “90” folder could be renamed to master2005.dacpac
    • This should be addressed in a future release of SSDT and could already be fixed.

  • If you use variables, don’t forget to replace any TSQL with the variable in the form of [$(VariableName)].
    • Square braces may not be necessary, but in most cases, they’ll work as expected for DB or Server names.
  • If you need to reference a dacpac that is already in use, you’ll need to create a copy of it. This comes up more often if you’re referencing a replicated database for which you already have a production dacpac.
  • Choose good variable names for the Server variable name.
  • Don’t forget to set the variables in the Project and/or Publication properties!

SSDT: SQL Project Options

To set the properties for your SQL Project, right-click the Project and select Properties. You’ll see a window containing several tabs to define your project.
 
Project Settings
Here you can set your normal target platform (SQL 2005, 2008, 2012, or Azure).
You can enable the T-SQL verification option, but this is mostly for Azure projects.
If you will generally output to a script, choose the “Create script” option. On the whole, just using the dacpac file will likely provide greater flexibility in the long run as it can be adapted to a different target. Generating a script will only be guaranteed to work against the target used to generate the script.
clip_image001
You can also set the dacpac file properties, which sadly do not do much when used against a database not using these as data-tier applications. There is some talk of enhancing the projects to use this version number and description somewhere within the database, but right now they are pretty much only there for you to populate if you wish.
clip_image002
 
You can also set the Database Settings for your project. These options are the normal ones you would set when setting options in SQL Server. You can choose to publish these to your targets so set these to your preferences. (More on that in a future post.)
clip_image003
clip_image004
clip_image005
I’m going to bypass the SQLCLR and SQLCLR Build tabs as I am not familiar with them and don’t currently use either in our system.
 
Build
The Build tab is the place to specify which warnings to ignore, the output path for your files when you build the project, and the name of the file. You may want to specify certain warnings to ignore, especially if you use cross-database projects or any references to system databases. Those can often result in warnings about missing objects, even though they’ll work perfectly fine when you publish them.

  • Note that the warnings are set per configuration. If you use multiple configurations be sure to set the warnings in each one.

clip_image006
 
clip_image006[1]
 
SQLCMD Variables
SQLCMD variables can be used throughout the project as placeholders for values passed in at publication time. For example, you may choose to change the way your scripts run based on your Development, Customer Acceptance, or Production environments. Define these variables here and use them wherever applicable in the project by inserting them as $(DeployType). SSDT will substitute them with the proper value on publication.
clip_image007
 
Build Events
Build events can be set up to run certain commands before and after the project is built. You can also choose to run the Post-Build event commands only when the project builds successfully or on every build.
 
Debug
Start Action and Target Connection String should make sense for those who need to change them. One item to note is that the debug action defaults to a SQL Express type instance of your database that is released to (localhost)\DBName. This will run within SSDT so you can try out your T-SQL before committing the changes in the project.
** Note that if you use FILESTREAM, you will not be able to use these user instances. You will need to change your debug database to a SQL Server install.
In your Deployment Options, you have a screen that looks something like this:
clip_image008
“Block incremental deployment” is one to be aware of. If you run into any constraints, refactoring, data type changes, NULL to NOT NULL, or similar changes, you could have your debug action stop unexpectedly. It can be really useful to avoid dropping columns that could contain data, but if you are aware of the changes, this option could also get in the way of normal releases. According to the MS documentation, this will only block the change if there is data in the table.
“DROP Objects in target but not in project” can be useful to make sure that everyone is running with what’s in the project and that they don’t have leftover objects that could interfere with testing. However, it’s also possible to lose a bunch of work if you publish a project with this option against your local instance containing the stored procedure you’ve worked on for the last 2 weeks.
“Advanced” contains a lot of different options about what to compare and how to generate the changes. Some of the more interesting options include:

  • Allow incompatible platform – this will let you push your changes to a version of SQL Server other than the one specified in the project properties. The changes will fail if you try to do something not allowed in the target, but useful in case you have your project set to the lowest version supported.
  • “Drop xyz not in source” – these options control what will be dropped from the target if it’s not defined in the source. The default options are likely good for most users.
  • “Ignore xyz” – defines what should be ignored when comparing the project against the target. You may want to ignore details about the partition schemes, or what permissions are set in the target
  • “Include Transactional Scripts” will set up the release script as transactions when publishing the database. This is useful when you want to make sure that if one part of the publish action fails, the change script is rolled back.
  • “Verify Deployment” – stops the publish actions if the script could run into some problems.

 
Reference Paths
This section is used to modify and maintain the various Server & Database variables used with cross-database references. See the “External Database References” page for more detail.
 
Code Analysis
This option can be useful to check for common issues such as using reserved words, non-standard characters in object names, or using “select *” in your queries. You can also specify whether to show these as errors or warnings. Set appropriately for your environment.