Deployment von SQL Server Database Project mit VS, MSBuild und TFS Build steuern
Der mit VS2010 eingeführte Projekttyp “SQL Server Database Project“ (.dbproj) erleichtert die Entwicklung von Datenbankprojekten enorm. Im Gegensatz zu den früheren „SQL Server Projects“ (.dbp), die nur als Container für SQL-Skripte dienten, verwaltet der neue Projekttyp einen versionierten Datenbankstand. Dieser kann zur Erzeugung eines inkrementellen Update Scripts genutzt werden [1].>> mehr…
Für die Erzeugung von Datenbanken bietet “SQL Server Database Project“ das neue Target “Deploy”, das die Datenbank im Zielserver installiert [2]. Für Solutions in automatisierten Umgebungen sind jedoch einige Hürden zu überwinden.
In diesem Artikel wird gezeigt, wie Datenbankdeployments durch Visual Studio, durch MsBuild Files und in einem TFS Build Agent Environment für Projekte und Solutions ausgeführt werden.
DB-Aktualisierung durch Visual Studio
Das lokale Deployment ist für den Entwickler recht einfach zu konfigurieren. In den Deploy Settings des Projekts können Datenbankserver und Datenbankname eingetragen werden. Der Benutzer muss sich nur noch entscheiden, ob er die Konfiguration als persönliche Einstellung oder als Projekteinstellung abspeichern möchte. In der Default-Einstellung werden Datenbankverbindungen als Projekteinstellungen gespeichert.
Verwendung von “My Isolated Development Environment”
Jeder Entwickler hat die Möglichkeit seine persönlichen Datenbankverbindungen im „Isolated Development Environment“ festzulegen. Die persönliche Konfiguration wird eingeschaltet, indem in den Deployment Settings des Datenbankprojektes „My isolated development environment“ ausgewählt wird. Alle darunter liegenden Einstellungen wie Beispielsweise „Target Connection“ oder „Target database name“ werden in dieser Konfiguration in den User-Settings gespeichert und bei einem Check-In nicht für andere Team-Kollegen übernommen.
Einstellen des “Isolated Development Environment”
Die Verwendung des Isolated Development Environment kann am Anfang recht verwirrend sein. Jede Kombination von VS Build Konfiguration und Isolated Development Environment führt zu einem eigenen Eintrag – entweder in der Projektdatei oder als persönliche Einstellung in den User Settings.
Deployment
Aus dem Context-Menü des Projektes, mit dem Befehl Deploy, startet der Entwickler den Prozess. Alle Änderungen („Delta“) zur existierenden Zieldatenbank werden ermittelt und als Deploy-Skript erzeugt [1]. Optional, unter Angabe von “Create a deployment script and deploy to the database”, wird das Skript zusätzlich in der Zieldatenbank ausgeführt.
Deploy aus dem Context Menu
Beim Starten einer Anwendung werden für alle Datenbankprojekte die Targets “Build” und “Deploy” aufgerufen. Dies kann eingeschränkt werden. Im Configuration Manager wird pro Build-Konfiguration festgelegt, welche Projekte gebaut und deployed werden. Enthält ein Datenbank-Deployment nur einfache, schnell durchzuführende Modifikationen auf der Datenbank, so wird man sie bei jedem Starten der Anwendung mit ausführen. Somit wird die Datenbank bei jedem Start auf einen aktuellen Stand gebracht.
Dies ist jedoch nicht immer wünschenswert. Enthält die Deploy-Aktion aufwändige Operationen wie z.B. das Replizieren einer Basisdatenbank, so wird man die Deploy-Aktion nur auf explizite Anforderung des Benutzers ausführen wollen und in den Build-Konfiguration deaktivieren.
Bei Starten der Anwendungen in der Debug Konfiguration werden Build und Deploy ausgeführt – solange die Haken gesetzt sind
DB-Aktualisierung durch MSBuild
In einer automatisierten Umgebung werden die Aktionen Build und Deploy von Skripten gesteuert. Die komplette Parametrisierung (welcher Server, welche Datenbank) wird als Parameter hinzugefügt.
Datenbanken in der Standardeinstellung (Entwicklung) erzeugen.
> Msbuild.exe /t:Build,Deploy MyDbOne.dbproj
Datenbank DbOne in einer anderen Datenbank erzeugen
> Msbuild.exe /t:Build,Deploy /p:TargetDatabase=MyOtherDb MyDbOne.dbproj
Der Parameter /t (Target) weisst MsBuild an, nicht nur das Default Target “Build” anzusteuern, sondern auch “Deploy” auszuführen. Mit der Option /p werden an MsBuild zusätzliche Parameter angegeben, die in Build Skripten ausgewertet werden können. Für Datenbankprojekte im Deploy Target werden unter anderem folgende Parameter verwendet:
- Configuration Build Configuration z.B. Debug oder Release
- UseSandboxSettings Entspricht dem Wert der DropDown “Configure deployment settings for” False => “My Settings” – Die Einstellungen aus dem Projektfile werden verwendet
True => „My Isolated Settings“ – Die Einstellungen aus den UserSettings werden verwendet - DeployToDatabase Entspricht der DropDown “Deploy action”
False => Das Delta-Skript wird erzeugt (Default)
True => Das Delta-Skript wird erzeugt und in der Zieldatenbank ausgeführt - TargetConnectionString => Datenbankserver
- TargetDatabase => Datenbankname
Für automatisierte Umgebungen gibt es die ganz klare Empfehlung die Sandbox Settings auszuschalten. Vergisst man dies, kann es zu unerwarteten Effekten kommen.
Das Deploy-Target funktioniert leider nicht für eine Solution. Eine Solution ist (noch) kein Msbuild-File und hat somit auch kein Deploy-Target das man ansteuern könnte. Nachfolgendes funktioniert nicht:
> Msbuild.exe MySolution.sln /t:Build,Deploy
Steuerung durch ein MsBuild File
Möchte man verschiedene Datenbankkonfigurationen wiederum selber in einem MsBuild File aufheben, so werden diese einem Projektfile hinzugefügt. Je nach Anwendungsfall bietet es sich, an hierfür ein eigenes MsBuild File schreiben, das die komplette Steuerung übernimmt. Im nachfolgenden Beispiel wird der Parameter „DbTargetConfiguration” ausgewertet, um DeployParameter für eine “Entwicklung”-Konfiguration oder alternativ für eine “TFS”-Konfiguration zu setzen.
Custom MsBuild File – “BuildMyDb.proj”
1: <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="All">
2: <Import Project="$(MSBuildToolsPath)Microsoft.Common.Targets" />
3:
4: <PropertyGroup>
5: <ProjectMyDbOne>MyDbOneMyDbOne.dbproj</ProjectMyDbOne>
6: <DeployToDatabase Condition="'$(DeployToDatabase)' == ''">True</DeployToDatabase>
7: <UseSandboxSettings Condition="'$(UseSandboxSettings)' == ''">False</UseSandboxSettings>
8: <DbTargetConfiguration Condition=" '$(DbTargetConfiguration)' == '' ">Entwicklung</DbTargetConfiguration>
9: </PropertyGroup>
10:
11: <PropertyGroup Condition=" '$(DbTargetConfiguration)' == 'Entwicklung' ">
12: <TargetConnectionString Condition="'$(TargetConnectionString)' == ''"
13: >Data Source=(local);Integrated Security=True;Pooling=False</TargetConnectionString>
14: <DatabaseNameDbOne Condition="'$(DatabaseNameDbOne)' == ''">MyDbOne</DatabaseNameDbOne>
15: <ParameterForUseInDbScripts Condition="'$(ParameterForUseInDbScripts)' == ''"
16: >Das ist die Datenbank fuer Entwicklung</ParameterForUseInDbScripts>
17: </PropertyGroup>
18:
19: <PropertyGroup Condition=" '$(DbTargetConfiguration)' == 'TFS' ">
20: <TargetConnectionString Condition="'$(TargetConnectionString)' == ''"
21: >Data Source=(local);Integrated Security=True;Pooling=False</TargetConnectionString>
22: <DatabaseNameDbOne Condition="'$(DatabaseNameDbOne)' == ''">MyDbOneTfs</DatabaseNameDbOne>
23: <ParameterForUseInDbScripts Condition="'$(ParameterForUseInDbScripts)' == ''"
24: >Das ist die Datenbank fuer TfsBuild</ParameterForUseInDbScripts>
25: </PropertyGroup>
26:
27: <Target Name="MyDbOneTarget">
28: <MSBuild Projects ="$(ProjectMyDbOne)"
29: ContinueOnError ="false"
30: Properties="Configuration=$(Configuration);
31: TargetDatabase=$(DatabaseNameDbOne);
32: TargetConnectionString=$([MSBuild]::Escape($(TargetConnectionString)));
33: UseSandboxSettings=$(UseSandboxSettings);
34: ParameterForUseInDbScripts=$(ParameterForUseInDbScripts);
35: DeployToDatabase=$(DeployToDatabase)"
36: Targets="clean;build;deploy"
37: >
38: <Output ItemName="OutputFiles" TaskParameter="TargetOutputs"/>
39: </MSBuild>
40: </Target>
41:
42: <Target Name="All" DependsOnTargets="MyDbOneTarget" />
43: </Project>
Im MsBuild File werden PorpertyGroups genutzt um Parameter der Datenbank zu verwalten. Das Target für die Datenbank (MyDbOneTarget) delegiert den Aufruf an das ausführende Datenbankprojekt. Bei der Weitergabe von Parametern muss darauf geachtet werden, daß diese ggf. in Escape-Formatierung weitergereicht werden müssen. Dies wird im Beispiel für den Parameter TargetConnectionString durchgeführt (siehe Zeile 32)
Deploy der Datenbank in der Defaultkonfiguration “Entwicklung”
> Msbuild.exe BuildMyDb.proj
Deploy der Datenbank in der Konfiguration “TFS”
> Msbuild.exe BuildMyDb.proj /p:DbTargetConfiguration=TFS
DB-Aktualisierung durch TFS Build Agent Environment
Automatisierte fachliche, integrative und oft auch Unit-Tests verlassen sich auf die Existenz von Datenbanken. Ich möchte hier gar nicht argumentieren ob das immer sinnvoll/richtig ist – die Projektrealitäten legen das meist fest. In der Konsequenz müssen die Datenbanken mit den Tests gebaut werden.
Als naheliegende Lösung versucht man im TFS den BuildParameter um das Target “Deploy” zu erweitern. Die Hoffnung, dass dadurch auch das Target “Deploy” auf den Datenbankprojekten ausgeführt wird erfüllt sich jedoch nicht: Solutions kennen kein Deploy Target
Somit muss ein alternatives Verfahren zur Erzeugung von Testdatenbanken gesucht werden. Hierzu gibt es unterschiedliche Ansätze:
- Der Testcase Setup erzeugt die Datenbank
- Das TFS Process Template wird um eine Datenbankerzeugung erweitert [3]
- Der Build wird über „Items to Build“ und “MSBuildArguments/Platform” gesteuert
Nach der reinen Lehre wäre das Erzeugen der Datenbank aus dem Testcase Setup als Verfahren zu bevorzugen. Die Aufgabe, die Datenbank zu erzeugen, wandert somit aber auch in den Aufruf der Testcases. Die Erzeugung eines Environments – und dazu zähle ich auch die Datenbanken – sollte aus meiner Sicht Teil des Build/Deploy und nicht Teil der Tests sein.
Möchte ich somit ersteres Verfahren im Projekt nicht verwenden, wird laut Internetrecherche meist das TFS Process Template erweitert [3]. Diese Lösung halte ich jedoch für unvorteilhaft, da ein „normaler“ Entwickler diesen Prozess nicht durchführen, testen und ändern kann. Auf einem Entwicklungsrechner ist die Umgebung des TFS-Build nicht vorhanden.
Von daher bevorzuge ich die Verwendung eines eigenen MsBuild Files. Dies lässt sich sehr bequem von Entwicklern, Skripten und TFS nutzen. Für den TFS Build werden die “Build Process Parameters” um nachfolgende Einträge erweitert:
Projects To Build: BuildMyDb.proj; MySolution.sln MSBuild Arguments: /p:DbTargetConfiguration=TFS /t:build,deploy
Mit diesen Parametern wird zusätzlich zur Solution noch das MsBuild File “BuildMyDb.proj” ausgeführt. Ein Entwickler kann dies selber testen, indem er das Datenbankprojekt direkt mit MsBuild aufruft.
Fazit
Das Deployment von Datenbanken in verschiedenen Umgebungen kann man durchaus dem neuen Projekttyp “SQL Server Database Project“ überlassen. Dies hat den Vorteil, dass sowohl der Entwickler wie auch automatisierte Umgebungen die gleichen Funktionen ausführen. Das Parameterisieren der einzelnen Umgebungen gestaltet sich derzeit noch schwierig, da das Deploy-Target per MsBuild auf Solutions nicht unterstützt wird. Mit eigenen MsBuild Files, die u.a. auch im TFS Umfeld eingesetzt werden können, kann man dieses Manko umgehen.
[1] SDX eXperts Flurfunk: Visual Studio Database Edtion: Deployment
[2] MSDN: An Overview of Database Build and Deployment
[3] Deploy a database Project with TFS build
Sie sehen gerade einen Platzhalterinhalt von Facebook. Um auf den eigentlichen Inhalt zuzugreifen, klicken Sie auf die Schaltfläche unten. Bitte beachten Sie, dass dabei Daten an Drittanbieter weitergegeben werden.
Mehr InformationenSie sehen gerade einen Platzhalterinhalt von Instagram. Um auf den eigentlichen Inhalt zuzugreifen, klicken Sie auf die Schaltfläche unten. Bitte beachten Sie, dass dabei Daten an Drittanbieter weitergegeben werden.
Mehr InformationenSie sehen gerade einen Platzhalterinhalt von X. Um auf den eigentlichen Inhalt zuzugreifen, klicken Sie auf die Schaltfläche unten. Bitte beachten Sie, dass dabei Daten an Drittanbieter weitergegeben werden.
Mehr Informationen