Skip to content

Commit

Permalink
Merge pull request #122 from JakeGinnivan/Docs
Browse files Browse the repository at this point in the history
Initial pass at docs
  • Loading branch information
JakeGinnivan committed Sep 11, 2015
2 parents 011a535 + 4691247 commit a8d8ef5
Show file tree
Hide file tree
Showing 16 changed files with 300 additions and 0 deletions.
14 changes: 14 additions & 0 deletions docs/contributing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Contributing to DbUp
If you would like to contribute to DbUp, look for [up-for-grabs](https://github.com/DbUp/DbUp/labels/up-for-grabs) issues, post a comment that you are working on it then submit a pull request.

Contributions to the docs and reporting of issues is also welcome.

## Testing
Because of the range of databases DbUp supports, it is not feasible to do automated integration testing. Instead DbUp takes a different approach:

* Use RecordingDbConnection
- RecordingDbConnection keeps a log of every opened transaction, executed command and other things we likely care about
- It is entirely in memory
* Use [ApprovalTests](https://github.com/approvals/ApprovalTests.Net) to approve the log of actions run against the database

This approach means we can exercise all the features in DbUp for all target databases without ever touching a real database. This approach does not test that the database driver is setup correctly and that DbUp can actually run commands against that database. But this is easy to test manually, is unlikely to ever break and would be reported/fixed very quickly.
2 changes: 2 additions & 0 deletions docs/faq.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# FAQ
Please contribute some FAQ's!
3 changes: 3 additions & 0 deletions docs/history.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DbUp began life as the database migration tool inside [FunnelWeb](https://github.com/funnelweblog/FunnelWeb), an open source ASP.NET MVC blog engine.

Despite its humble origins, growing up, DbUp always thought it could aspire to something bigger. Now it is out in the world on its own, making its own way in life, the little script runner that could.
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DbUp is a .NET library that helps you to deploy changes to SQL Server databases. It tracks which SQL scripts have been run already, and runs the change scripts that are needed to get your database up to date.
28 changes: 28 additions & 0 deletions docs/more-info/journaling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
By default, DbUp adds a table to your SQL Server database called SchemaVersions, which tracks the scripts that have already been executed. Before running, DbUp checks this table to work out which scripts should be skipped. After running, it inserts journal records to record the scripts that have been run.

![Schema Versions](./schema-versions.png)

You can change the schema and/or name of this table using the `JournalToSqlTable` extension method:

``` csharp
DeployChanges.To
.SqlDatabase(connectionString)
.JournalToSqlTable("MySchema", "MyTable")
.Build();
```

## NullJournal
If you want to always apply certain scripts -- typically **idempotent** scripts that drop and create things like functions, views, procedures, and permissions -- you can use the `NullJournal` class:

``` csharp
DeployChanges.To
.SqlDatabase(connectionString)
.WithScriptsEmbeddedInAssembly(
Assembly.GetExecutingAssembly(),
s => s.Contains("everytime"))
.JournalTo(new NullJournal())
.Build();
```

## Custom Journal
You can also implement your own `IJournal` to track the scripts yourself. Most parts of DbUp are extensible in this way; just browse the API to see what it can do.
10 changes: 10 additions & 0 deletions docs/more-info/logging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Logging
DbUp has a simple logging abstraction in place using the `IUpgradeLog` interface. Out of the box there are the following loggers:

* `ConsoleUpgradeLog` - Logs to `Console.Write*`
- Use `builder.LogToConsole()` to register
* `SqlContextUpgradeLog` - Logs to `SqlContext`
- Use `builder.LogToSqlContext()` to register
* `TraceUpgradeLog` - Logs to `Trace.Write*`
- Use `builder.LogToTrace()` to register
* Use `builder.LogTo(new MyCustomLogger())` to provide your own logger
17 changes: 17 additions & 0 deletions docs/more-info/preprocessors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Pre-Processors
Script Pre-Processors are a really handy extensibility hook into DbUp, it allows you to modify a script before it is executed. Some examples of how this can/is used:

* Variable Substitution
* Replacing incompatible types
- For SqlCe/SQLite we automatically replace `nvarchar(max)` with `ntext`
* Stripping the $schema$. variable out of databases which do not support schemas

## Writing your own
To create your own pre-processor just implement the `IScriptPreprocessor` interface then register is with your DbUp builder:

``` csharp
DeployChanges
.To
.SqlDatabase(..)
.WithPreProcessor(new MyPreprocessor())
```
Binary file added docs/more-info/schema-versions.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 37 additions & 0 deletions docs/more-info/script-providers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Script Providers
DbUp can get it's scripts which need to be executed from anywhere. Out of the box it has support for:

* **EmbeddedScriptProvider**
Finds scripts embedded in a single Assembly
- Usage: `builder.WithScriptsEmbeddedInAssembly(Assembly, [optional filter])`
- Example: `builder.WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly(), (string s) => s.StartsWith("Script"))`
* **EmbeddedScriptsProvider**
Finds scripts embedded in one or more assemblies
- Usage: `builder.WithScriptsEmbeddedInAssemblies(Assembly[], [optional filter])`
- Example:
```
builder.WithScriptsEmbeddedInAssemblies(new[]
{
Assembly.GetExecutingAssembly(),
typeof(Something).Assembly
},
(string s) => s.StartsWith("Script"))
```
* **FileSystemScriptProvider**
Finds scripts in a specified directory
Usage: `builder.WithScriptsFromFileSystem(path)`
* **StaticScriptProvider**
Allows you to easily programatically supply scripts from code
- Usage:
``` csharp
// Single script
builder.WithScript("name.sql", "content");
// Many scripts
builder.WithScripts(new[]
{
new SqlScript("script1.sql", "content"),
new SqlScript("script2.sql", "content2")
});
// Custom script provider
builder.WithScripts(new MyCustomScriptProvider());
```
6 changes: 6 additions & 0 deletions docs/more-info/transactions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Transactions
DbUp v3.0 added support for transactions. Not all changes can be rolled back, but for many DDL and data changes transactions work fine. Out of the box there are 3 strategies:

* No Transactions (**default**) - `builder.WithoutTransaction()`
* Transaction per script - `builder.WithTransactionPerScript()`
* Single transaction - `builder.WithTransaction()`
18 changes: 18 additions & 0 deletions docs/more-info/variable-substitution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Variable Substitution
DbUp supports basic variable substitution, to enable you should register variables when configuring DbUp:

``` csharp
DeployChanges.To
.SqlDatabase(..)
.WithVariable("TestVariable", "Value")
```

The in your database script:

```
print '$TestVariable$'
```

Will execute `print 'Value'`

**Note:** there is no way to escape variables, if this causes you issues, create a GitHub issue or submit a pull request to allow escaping!
88 changes: 88 additions & 0 deletions docs/philosophy-behind-dbup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# How to deploy a database
*This post was originally posted on [Paul Stovell's blog](http://paulstovell.com/blog/database-deployment) under the same title as this page. It has been copied to the DbUp docs so it is with the rest of the documentation and can be evolved over time.*

When I'm building an application that stores data, there are a few things I try to make sure we can do when it comes to managing the lifecycle of our storage. I'm going to focus on SQL Server, but this applies to other relational storage.

# What's in a database?
Even outside of production, a database is more than schema. A database "definition" consists of:

* The database schema (tables, views, procedures, schemas)
* [Reference data](http://en.wikipedia.org/wiki/Reference_data) (ZIP codes, salutations, other things I expect to always "be there")
* Sample master/transactional data (for developers/testers)
* Security (roles, permissions, users)

It may even include management job definitions (backup, shrink), though they tend to be left to DBA's.

# Transitions, not States
As each iteration progresses, we'll make changes to our database.

One approach to upgrading existing databases is to "diff" the old state of the database with our new state, and then to manually modify this diff until we have something that works. We then employ the "hope and pray" strategy of managing our database, which generally means "leave it to the DBA" for production. Tools like [Red Gate SQL Compare](http://www.red-gate.com/products/SQL_Compare/) and [Visual Studio Database Edition](http://blogs.msdn.com/b/gertd/archive/2008/11/25/visual-studio-team-system-2008-database-edition-gdr-rtm.aspx) encourage this approach.

I never understood the state or model-driven approach, and I'll explain why. Here's a simple example of some T-SQL:

```sql
create table dbo.Customer (
Id int not null identity(1,1) constraint PK_CustomerId primary key,
FullName nvarchar(200) not null
);
```

See the "create table"? That's not a definition - it's an instruction. If I need to change my table, I don't change the statement above. I just write:

``` sql
alter table dbo.Customer
add IsPreferred bit not null
constraint DF_Customer_IsPreferred default(0);
```

Again, an instruction. A transition. I don't tell the database what the state is - I tell it how to get there. I can provide a lot more context, and I have a lot more power.

You'll note that I used a default constraint above - that's because my table might have had data already. Since I was thinking about transitions, I was forced to think about these issues.

Our databases are designed for transitions; attempting to bolt a state-based approach on them is about as dumb as [bolting a stateful model on top of the web](http://weblogs.asp.net/infinitiesloop/archive/2006/08/03/Truly-Understanding-Viewstate.aspx) (and Visual Studio Database Edition is about as much fun as ViewState).

Keep in mind that making changes to databases can be complicated. Here are some things we might do:

* Add a column to an existing table (what will the default values be?)
* Split a column into two columns (how will you deal with data in the existing column?)
* Move a column from one table onto another (remember to move it, not to drop and create the column and lose the data)
* Duplicate data from a column on one table into a column on another (to reduce joins) (don't just create the empty column - figure out how to get the data there)
* Rename a column (don't just create a new one and delete the old one)
* Change the type of a column (how will you convert the old data? What if some rows won't convert?)
* Change the data within a column (maybe all order #'s need to be prefixed with the customer code?)

You can see how performing a "diff" on the old and new state can miss some of the intricacies of real-life data management.

# Successful database management
Here are some things I want from my database deployment strategy:

1. **Source controlled**
Your database isn't in source control? You don't deserve one. Go use Excel.
2. **Testability**
I want to be able to write an integration test that takes a backup of the old state, performs the upgrade to the current state, and verifies that the data wasn't corrupted.
3. **Continuous integration**
I want those tests run by my build server, every time I check in. I'd like a CI build that takes a production backup, restores it, and runs and tests any upgrades nightly.
4. **No shared databases**
Every developer should be able to have a copy of the database on their own machine. Deploying that database - with sample data - should be one click.
5. **Dogfooding upgrades**
If Susan makes a change to the database, Harry should be able to execute her transitions on his own database. If he had different test data to her, he might find bugs she didn't. Harry shouldn't just blow away his database and start again.

The benefits to this are enormous. By testing my transitions **every single day** - on my own dev test data, in my integration tests, on my build server, against production backups - I'm going to be confident that my changes will work in production.

# Versions table
There should be something that I can query to know which transitions have been run against my database. The simplest way is with a `Versions` table, which tells me the scripts that were run, when they were run, and who they were run by.

When it comes to upgrading, I can query this table, skip the transitions that have been run, and execute the ones that haven't.

# Sample data
Development teams often need access to a good set of sample data, ideally lots of it. Again, these should be transition scripts that can be optionally run (since I might not want sample data in production), and in source control.

# Document Databases
Most of these principles apply to document databases too. In fact, in some ways the problems are harder. While you don't have a fixed schema, you're probably mapping your documents to objects - what if the structure of the objects change? You _may_ need to run transitional scripts over the document database to manipulate the existing documents. You may also need to re-define your indexes. You want those deployment scenarios to be testable and trusted.

# Migration libraries
Rails popularized the approach of [using a DSL to describe data migrations](http://guides.rubyonrails.org/migrations.html). There are a number of .NET ports of this concept, like [Fluent Migrator](https://github.com/schambers/fluentmigrator) and [Machine.Migrations](http://blog.eleutian.com/2008/04/25/AFirstLookAtMachineMigrations.aspx).

Personally, I actually find T-SQL a perfectly good DSL for describing data migrations. I love my ORM's, but for schema work, T-SQL is perfectly adequate.

Again, these libraries focus on transitions (create table, add column), not states, so they're useful, unlike Visual Studio Database Edition, which isn't.
21 changes: 21 additions & 0 deletions docs/supported-databases.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Supported Databases
DbUp supports a number of different databases, the platforms are also listed under each database.

* Sql Server 2000, 2005, 2008, 2012, 2014, 2016
* Sql Azure
- >= .NET 3.5
* SQLite
- >= .NET 3.5
* SQLite.Mono (Same as above, but using Mono driver)
- .NET 4.0
- Coming soon: Xamarin, PCL and other targets
* SqlCe
- >= .NET 4.0
* MySql
- >= .NET 3.5
* PostgreSQL
- >= .NET 4.0
* Firebird
- >= .NET 4.0
If you would like to see a new database or a new target platform, please [submit a pull request](./contributing.md)
34 changes: 34 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Using DbUp
DbUp uses a builder to configure your database deployments, you then build the upgrade engine and run your database migrations.

## Configuration
The entrypoint is `DeployChanges.To`. There are then extension methods for all of the [supported databases](./supported-databases.md).

Then you can configure:

* [Journaling](./journaling.md)
* [Script Providers](./script-providers.md)
* [Logging](./logging.md)
* [Variable Substitution](./variable-substitution.md)
* [Transaction Usage](./transactions.md)
* [Preprocessors](./preprocessors.md)

## Deploying
Once you have configured DbUp

``` csharp
var upgradeEngine = DeployChanges.To
.SqlDatabase(connectionString)
.WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly())
.LogToConsole()
.Build();
```

You can:
* Get scripts which will be executed (`GetScriptsToExecute()`)
* Get already executed scripts (`GetExecutedScripts()`)
* Check if an upgrade is required (`IsUpgradeRequired()`)
* Creates version record for any new migration scripts without executing them (`MarkAsExecuted`)
* Useful for bringing development environments into sync with automated environments
* Try to connect to the database (`TryConnect()`)
* Perform the database upgrade (`PerformUpgrade()`)
20 changes: 20 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
site_name: GitVersion
theme: readthedocs
repo_url: https://github.com/DbUp/DbUp

pages:
- Home: index.md
- History: history.md
- Philosophy Behind DbUp: philosophy-behind-dbup.md
- Usage: usage.md
- Supported Databases: supported-databases.md
- FAQ: faq.md
- Contributing: contributing.md

- More Info:
- Script Providers: more-info/script-providers.md
- Trasactions: more-info/transactions.md
- Pre-Processors: more-info/preprocessors.md
- Logging: more-info/logging.md
- Journaling: more-info/journaling.md
- Variable Substitution: more-info/variable-substitution.md
1 change: 1 addition & 0 deletions src/DbUp/Engine/Transactions/DatabaseConnectionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ protected DatabaseConnectionManager(Func<IUpgradeLog, IDbConnection> connectionF
protected DatabaseConnectionManager(IConnectionFactory connectionFactory)
{
this.connectionFactory = connectionFactory;
TransactionMode = TransactionMode.NoTransaction;
transactionStrategyFactory = new Dictionary<TransactionMode, Func<ITransactionStrategy>>
{
{TransactionMode.NoTransaction, ()=>new NoTransactionStrategy()},
Expand Down

0 comments on commit a8d8ef5

Please sign in to comment.