Access Build variables inside Pre and Post deployment scripts SSDT - sql-server

I have just set up an SSDT project which I want to use to create local databases on the SQL server hosted locally on my machine.
I want to add some pre- and post- deployment SQL scripts for initialization and cleanups.
Since, the server and the database name can change, I have defined two build variables using the project properties each for the target server and target database.
However, I can't seem to access them inside the post deployment scripts.
The syntax below won't build the project -
use [$(TargetDatabaseName)]
This builds, but then fails while publishing -
use ['$(TargetDatabaseName)']
and the error says the ''myTargetDB'' doesn't exist (myTargetDB was passed as a value at the time of publishing)
This might be a trivial thing but I am just not able to get around it. I am on SQL server 2016 if that matters.

Make sure that you put both scripts in SQLCMD mode. See the image below surrounding with red.
Once your target variable is defined, see surrounding with blue in the image above, it can be safely used in the PostDeployment script, see the image below surrounding with blue.
If you have any questions, feel free to contact me.

There is a predefined variable, $(DatabaseName), for the name of the target database. You don't need to create your own; and even if you do, you would need to set the same value to both of them.
Not sure about the target server. In most cases, SQL scripts are generated with the assumption that connection to the correct server is already established. Sure, you can change the current server using something like :connect $(TargetServerName), but I think it will only lead to confusion (and I'm not sure it will work, actually).
The only exception I can think of is that you can't use SQLCMD variables to parameterise the logical/physical names of the database files - these have to be hardcoded.
All other variables, if declared in the project properties, should be accessible everywhere. Below is a fragment of a post deploy from one of my projects:
use [master];
go
print 'Switching database ownership to sa...';
GO
alter authorization on database::[$(DatabaseName)] to [sa];
go
use [$(DatabaseName)];
go
print 'Creating database master key...';
go
-- Create database master key
create master key encryption by password = '$(DMK_Key)';
go
print 'Running database setup...';
go
exec dbo.init_database;
go
It is possible, however, that you are trying to reference another database, located on a different server. If that's the case, you need to follow a different approach, namely: built a project for that remote database and add its DACPAC to the list of project references, using the Add database reference... menu. There, you will be able to specify variables for both the (linked) server and the database name.

Related

How to create database using Database Project in Visual Studio if doesn't exists?

I have a Database project for my personal project and I am trying to deploy my code to my DEV server. I frequently delete and re-create my DEV Server. Right now, DEV Server is newly created with SQL Server. Every time I want to deploy my code I have to manually create Database Project and then publish database project. I want to automate creation of Database with database project deployment.
Right now, I have a script that creates database, but I have to execute it manually. And this is working perfectly but I want to automate this step as well.
Is this even possible? If yes, then how? Please explain step by step. Also what will we mention for Initial Catalog in connection string?
Edit:
I tried to create Database by using
CREATE DATABASE LocalDbTest
in Pre-Deployment Script. But it didn't work. It is creating Database, but then tables are not getting created tables under it. Since I used master database as default database, it is creating table under master. It is not letting me select LocalDbTest database as default because it is not yet created, so I have to select Master as my default database. I tried to Change Database by:
USE LocalDbTest
GO
I used it just after creating Database but this didn't work because when generating script it is changing back to default database. This part is coming automatically when generating script.
USE [$(DatabaseName)];
GO
Also Visual Studio is not letting me add database name in front of table name like:
CREATE TABLE [LocalDbTest].[dbo].[TestTable]
I am getting error:
When you create an object of this type in a database project, the object's name must contain no more than two parts.
If you have a script ready for database creation, you can use the Pre-build event to call SQLCMD and run your script.
Edit:
If you have trouble pointing to a database that does not exist, you may have to manually edit the publish profile (ex. dev.publish.xml) and set the TargetDatabaseName element explicitly. You can also set CreateNewDatabase element to True if you want to be recreated every time it gets published.
Answer:
You can use a publish profile and hardcode the target database in it.

Can I manage database using database project without knowing connection string?

I have created database project. I am able to upgrade my changes in my sql server. Now I have deploy the same changes on another environment. Also I dont want to change my previous data. I dont have to access that Sql server so I don`t know the connection string.
I have some options, like to deploy the .dacpac file or .sql script, but it first delete the database then creates new one. So that I loosing my data.
Please help me. If any option is there?
The options I see for this are:
Ask for a backup (or extract schema tables using task-->Generate scripts ion ssms) - restore this somewhere and use sqlpackage to generate a deployment script you can ask them to run
Ask them to run sqlpackage.exe and either generate a script or run it directly
Ask them for permissions so you can do it
If the database is being deleted then you have the option "CreateNewDatabase" set to true which would be bad in a production environment so remove it or set it to false!
If they run it or you ask for permissions, these are the minimum permissions you need to generate a script (to run the script you will probably need dbo):
https://the.agilesql.club/Blogs/Ed-Elliott/What-Permissions-Do-I-Need-To-Generate-A-Deploy-Script-With-SSDT (my blog)

Scripting FileTables

Scenario:
I have 3 environments that I am using, Dev, UAT and Live. Each of which having it's own database, MyDb_Dev, MyDb_UAT, MyDb_Live.
Then I have a VS2012 Database project in my solution that contains all my scripts. This works nicely when I make changes to my model database (MyDb_Model) that is located locally.
What I want to do:
I want to use the FileTables in SQL 2012 (which I understand how to set up), however I don't know how to script them to be able to configure the options to handle my environments. When I generate the scripts, it will hard code the name to be MyDb_Model as the FileGroup. Also, that said, when I do try and publish to my Dev database, it's complaining about the database options not being able to take the new scripts. When I script include the options of the Model database, it'll complain when I try to publish to my Dev database because of duplicating names.
Question:
Can you script FileTables (with the database options) using the database project in V2012 to be configurable or do I need to manually make my own scripts?
Prefered:
Compare MyDb_Model to Database project.
Publish to MyDb_Dev as a newly created database.
Sounds like you'll want project variables to handle this where the variable contains the environment-specific text for each. You'd then use that variable in your objects instead of the hard-coded paths. The following would create a FileTable called "DocumentStore" and use the value for a variable called "FileTableDirectoryVariable" that you set up in your Project Properties - SQLCMD Variables. Set each of those in your Publish Profiles to use the correct directory, and you should be good. If you're using different filegroups for these tables, you should be able to tweak the FileGroup setting in a similar manner using a SQLCMD Variable.
CREATE TABLE DocumentStore AS FileTable
WITH (
FileTable_Directory = '$(FileTableDirectoryVariable)',
FileTable_Collate_Filename = database_default
);
GO

How do you prevent a VS2010 Database Project Deployment from generating a drop database?

Suppose you have a database project and you do NOT have "Always re-create database" checked off in your Database.sqldeployment settings. And suppose you deploy to a server that already has a database by the name of the one you are deploying.
Under what other circumstances will the database deploy generate a script with a "DROP DATABASE" statement?
If you don't ever, ever, ever want your database to be dropped by the deployment script generated by right clicking your database project and selecting "Deploy", what are some of the steps you can take to prevent this?
In addition to the "Always re-create database" NOT being checked off, you should also check the Development tab on your database project's Properties page. Make sure you define a target connection. When you don't define one the project will always and only deploy as-if the target database does not exist. This behavior is by design. see this link for more details.
My suggestion is to create the connection using Windows Authentication so each user would have access to the extend they are supposed to.
Also please note that you will have to do this for each Deployment Configuration (e.g. Debug, Release, etc.)
I personally set the deploy action to just create a script and run it manually to be on the safe side!

Visual Studio 2010 Database Project Deploy to Different Environments

I've got a Database project which works fine for my local MSSQL 2008 database.
It has a script under scripts/post-deployment that inserts standing data configuration into a settings table, and other tables. I've got 1 file for each table, e.g. a Setting.sql file to insert data into the Settings table.
The settings will be different depending on the database I deploy to.
How can I script this? Basicaly I would like to be able to have say 2 files,
Prod.Setting.sql and Dev.Setting.sql and VS 2010 would use the appropriate script depending on what database (environment) I am deploying to.
Completely doable but there two options and a few steps involved. You can have a complete duplicate set of scripts, one for each configuration. Or, you can have one set of scripts, the contents of which take into account the configuration you are using. I'll go with the first, and I'll keep it simple.
Create two solution configurations, or use Debug and Release if you like. I'll use these for the example.
For each configuration, create a new .sqlcmdvars file.
Database_Release.sqlcmdvars
Database_Debug.sqlcmdvars
Switch your solution configuration to each and in the database project properties change the variables file drop down to point at the corresponding file you created.
In each of those files you can define variables to be used during deployment. Create a new variable in each one
$(DeploymentConfiguration)
And set its value in each one to either Debug or Release
Then in any of your Pre or Post deployment scripts you can do something like so:
IF '$(DeploymentConfiguration)' = 'Debug'
BEGIN
PRINT 'Executing Debug deployment'
:r .\Debug\SomeNeededScript.sql
END
IF '$(DeploymentConfiguration)' = 'Release'
BEGIN
PRINT 'Executing Release deployment'
:r .\Release\Anotherscript.sql
END

Resources