Fix migrations for SqlServer

This commit is contained in:
Stephan
2019-05-28 17:49:50 +02:00
parent 457427a5f4
commit 49d2a6dbf0
14 changed files with 97 additions and 33 deletions

View File

@@ -34,6 +34,16 @@ namespace Umbraco.Core.Migrations.Expressions.Create.KeysAndIndexes
ExecuteSql(sql);
foreach (var sql in syntax.Format(tableDefinition.ForeignKeys))
ExecuteSql(sql);
// note: we do *not* create the DF_ default constraints
/*
foreach (var column in tableDefinition.Columns)
{
var sql = syntax.FormatDefaultConstraint(column);
if (!sql.IsNullOrWhiteSpace())
ExecuteSql(sql);
}
*/
}
private void ExecuteSql(string sql)

View File

@@ -10,9 +10,13 @@ namespace Umbraco.Core.Migrations.Expressions.Delete.DefaultConstraint
IDeleteDefaultConstraintOnTableBuilder,
IDeleteDefaultConstraintOnColumnBuilder
{
public DeleteDefaultConstraintBuilder(DeleteDefaultConstraintExpression expression)
private readonly IMigrationContext _context;
public DeleteDefaultConstraintBuilder(IMigrationContext context, DeleteDefaultConstraintExpression expression)
: base(expression)
{ }
{
_context = context;
}
/// <inheritdoc />
public IDeleteDefaultConstraintOnColumnBuilder OnTable(string tableName)
@@ -24,6 +28,8 @@ namespace Umbraco.Core.Migrations.Expressions.Delete.DefaultConstraint
/// <inheritdoc />
public IExecutableBuilder OnColumn(string columnName)
{
var defaultConstraint = _context.SqlContext.SqlSyntax.GetDefaultConstraint(_context.Database, Expression.TableName, columnName);
Expression.ConstraintName = defaultConstraint ?? string.Empty;
Expression.ColumnName = columnName;
return new ExecutableBuilder(Expression);
}

View File

@@ -1,5 +1,4 @@
using NPoco;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Migrations.Expressions.Common;
using Umbraco.Core.Migrations.Expressions.Delete.Column;
using Umbraco.Core.Migrations.Expressions.Delete.Constraint;
@@ -30,19 +29,19 @@ namespace Umbraco.Core.Migrations.Expressions.Delete
}
/// <inheritdoc />
public IExecutableBuilder KeysAndIndexes<TDto>(bool pk = true, bool fk = true, bool ix = true)
public IExecutableBuilder KeysAndIndexes<TDto>(bool local = true, bool foreign = true)
{
var syntax = _context.SqlContext.SqlSyntax;
var tableDefinition = DefinitionFactory.GetTableDefinition(typeof(TDto), syntax);
return KeysAndIndexes(tableDefinition.Name, pk, fk, ix);
return KeysAndIndexes(tableDefinition.Name, local, foreign);
}
/// <inheritdoc />
public IExecutableBuilder KeysAndIndexes(string tableName, bool pk = true, bool fk = true, bool ix = true)
public IExecutableBuilder KeysAndIndexes(string tableName, bool local = true, bool foreign = true)
{
if (tableName.IsNullOrWhiteSpace())
throw new ArgumentNullOrEmptyException(nameof(tableName));
return new DeleteKeysAndIndexesBuilder(_context) { TableName = tableName, DeletePrimaryKey = pk, DeleteForeignKeys = fk, DeleteIndexes = ix};
return new DeleteKeysAndIndexesBuilder(_context) { TableName = tableName, DeleteLocal = local, DeleteForeign = foreign };
}
/// <inheritdoc />
@@ -111,7 +110,7 @@ namespace Umbraco.Core.Migrations.Expressions.Delete
public IDeleteDefaultConstraintOnTableBuilder DefaultConstraint()
{
var expression = new DeleteDefaultConstraintExpression(_context);
return new DeleteDefaultConstraintBuilder(expression);
return new DeleteDefaultConstraintBuilder(_context, expression);
}
}
}

View File

@@ -10,12 +10,16 @@ namespace Umbraco.Core.Migrations.Expressions.Delete.Expressions
public virtual string TableName { get; set; }
public virtual string ColumnName { get; set; }
public virtual string ConstraintName { get; set; }
protected override string GetSql()
{
return string.Format(SqlSyntax.DeleteDefaultConstraint,
SqlSyntax.GetQuotedTableName(TableName),
SqlSyntax.GetQuotedColumnName(ColumnName));
return ConstraintName.IsNullOrWhiteSpace()
? string.Empty
: string.Format(SqlSyntax.DeleteDefaultConstraint,
SqlSyntax.GetQuotedTableName(TableName),
SqlSyntax.GetQuotedColumnName(ColumnName),
SqlSyntax.GetQuotedName(ConstraintName));
}
}
}

View File

@@ -21,12 +21,12 @@ namespace Umbraco.Core.Migrations.Expressions.Delete
/// <summary>
/// Builds a Delete Keys and Indexes expression, and executes.
/// </summary>
IExecutableBuilder KeysAndIndexes<TDto>(bool pk = true, bool fk = true, bool ix = true);
IExecutableBuilder KeysAndIndexes<TDto>(bool local = true, bool foreign = true);
/// <summary>
/// Builds a Delete Keys and Indexes expression, and executes.
/// </summary>
IExecutableBuilder KeysAndIndexes(string tableName, bool pk = true, bool fk = true, bool ix = true);
IExecutableBuilder KeysAndIndexes(string tableName, bool local = true, bool foreign = true);
/// <summary>
/// Specifies the column to delete.

View File

@@ -18,11 +18,9 @@ namespace Umbraco.Core.Migrations.Expressions.Delete.KeysAndIndexes
public string TableName { get; set; }
public bool DeletePrimaryKey { get; set; }
public bool DeleteLocal { get; set; }
public bool DeleteForeignKeys { get; set; }
public bool DeleteIndexes { get; set; }
public bool DeleteForeign { get; set; }
/// <inheritdoc />
public void Do()
@@ -30,19 +28,26 @@ namespace Umbraco.Core.Migrations.Expressions.Delete.KeysAndIndexes
_context.BuildingExpression = false;
// drop keys
if (DeleteForeignKeys || DeletePrimaryKey)
if (DeleteLocal || DeleteForeign)
{
var keys = _context.SqlContext.SqlSyntax.GetConstraintsPerTable(_context.Database).DistinctBy(x => x.Item2).ToList();
if (DeleteForeignKeys)
foreach (var key in keys.Where(x => x.Item1 == TableName && x.Item2.StartsWith("FK_")))
// table, constraint
var tableKeys = _context.SqlContext.SqlSyntax.GetConstraintsPerTable(_context.Database).DistinctBy(x => x.Item2).ToList();
if (DeleteForeign)
{
foreach (var key in tableKeys.Where(x => x.Item1 == TableName && x.Item2.StartsWith("FK_")))
Delete.ForeignKey(key.Item2).OnTable(key.Item1).Do();
if (DeletePrimaryKey)
foreach (var key in keys.Where(x => x.Item1 == TableName && x.Item2.StartsWith("PK_")))
}
if (DeleteLocal)
{
foreach (var key in tableKeys.Where(x => x.Item1 == TableName && x.Item2.StartsWith("PK_")))
Delete.PrimaryKey(key.Item2).FromTable(key.Item1).Do();
// note: we do *not* delete the DEFAULT constraints
}
}
// drop indexes
if (DeleteIndexes)
if (DeleteLocal)
{
var indexes = _context.SqlContext.SqlSyntax.GetDefinedIndexesDefinitions(_context.Database).DistinctBy(x => x.IndexName).ToList();
foreach (var index in indexes.Where(x => x.TableName == TableName))

View File

@@ -67,9 +67,9 @@
// delete *all* keys and indexes - because of FKs
// on known v7 tables only
foreach (var table in tables)
Delete.KeysAndIndexes(table, false, true, false).Do();
Delete.KeysAndIndexes(table, false, true).Do();
foreach (var table in tables)
Delete.KeysAndIndexes(table, true, false, true).Do();
Delete.KeysAndIndexes(table, true, false).Do();
}
}
}

View File

@@ -15,7 +15,12 @@
Database.Execute("set identity_insert umbracoUser on;");
Database.Execute(@"
insert into umbracoUser select
insert into umbracoUser (id,
userDisabled, userNoConsole, userName, userLogin, userPassword, passwordConfig,
userEmail, userLanguage, securityStampToken, failedLoginAttempts, lastLockoutDate,
lastPasswordChangeDate, lastLoginDate, emailConfirmedDate, invitedDate,
createDate, updateDate, avatar, tourData)
select
-1 id,
userDisabled, userNoConsole, userName, substring(userLogin, 1, len(userLogin) - 2) userLogin, userPassword, passwordConfig,
userEmail, userLanguage, securityStampToken, failedLoginAttempts, lastLockoutDate,

View File

@@ -213,8 +213,10 @@ WHERE versionId NOT IN (SELECT (versionId) FROM {PreTables.ContentVersion} WHERE
Delete.Column("text").FromTable(PreTables.Document).Do();
Delete.Column("templateId").FromTable(PreTables.Document).Do();
Delete.Column("documentUser").FromTable(PreTables.Document).Do();
Delete.DefaultConstraint().OnTable(PreTables.Document).OnColumn("updateDate").Do();
Delete.Column("updateDate").FromTable(PreTables.Document).Do();
Delete.Column("versionId").FromTable(PreTables.Document).Do();
Delete.DefaultConstraint().OnTable(PreTables.Document).OnColumn("newest").Do();
Delete.Column("newest").FromTable(PreTables.Document).Do();
// add and populate edited column

View File

@@ -44,7 +44,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
string TruncateTable { get; }
string CreateConstraint { get; }
string DeleteConstraint { get; }
string DeleteDefaultConstraint { get; }
string FormatDateTime(DateTime date, bool includeTime = true);
string Format(TableDefinition table);
@@ -106,5 +106,14 @@ namespace Umbraco.Core.Persistence.SqlSyntax
/// A Tuple containing: TableName, IndexName, ColumnName, IsUnique
/// </returns>
IEnumerable<Tuple<string, string, string, bool>> GetDefinedIndexes(IDatabase db);
/// <summary>
/// Gets the name of the default constraint on a column.
/// </summary>
/// <param name="db">The database.</param>
/// <param name="tableName">The table name.</param>
/// <param name="columnName">The column name.</param>
/// <returns>The name of the default constraint, or the empty string if there is no default constraint.</returns>
string GetDefaultConstraint(IDatabase db, string tableName, string columnName);
}
}

View File

@@ -132,6 +132,16 @@ ORDER BY TABLE_NAME, INDEX_NAME");
item => new Tuple<string, string, string, bool>(item.TABLE_NAME, item.INDEX_NAME, item.COLUMN_NAME, item.UNIQUE));
}
/// <inheritdoc />
public override string GetDefaultConstraint(IDatabase db, string tableName, string columnName)
{
// cannot return a true default constraint name (does not exist on SqlCe)
// but we won't really need it anyways - just check whether there is a constraint
var hasDefault = db.Fetch<bool>(@"select column_hasdefault from information_schema.columns
where table_name=@0 and column_name=@1", tableName, columnName).FirstOrDefault();
return hasDefault ? "XXXXX" : string.Empty;
}
public override bool DoesTableExist(IDatabase db, string tableName)
{
var result =
@@ -175,7 +185,7 @@ ORDER BY TABLE_NAME, INDEX_NAME");
{
get
{
return "ALTER TABLE [{0}] ALTER COLUMN [{1}] DROP DEFAULT";
return "ALTER TABLE {0} ALTER COLUMN {1} DROP DEFAULT";
}
}

View File

@@ -225,6 +225,17 @@ order by T.name, I.name");
}
/// <inheritdoc />
public override string GetDefaultConstraint(IDatabase db, string tableName, string columnName)
{
return db.Fetch<string>(@"select con.[name] as [constraintName]
from sys.default_constraints con
join sys.columns col on con.object_id=col.default_object_id
join sys.tables tbl on col.object_id=tbl.object_id
where tbl.[name]=@0 and col.[name]=@1;", tableName, columnName)
.FirstOrDefault() ?? string.Empty;
}
public override bool DoesTableExist(IDatabase db, string tableName)
{
var result =
@@ -276,7 +287,7 @@ order by T.name, I.name");
return null;
}
public override string DeleteDefaultConstraint => "ALTER TABLE [{0}] DROP CONSTRAINT [DF_{0}_{1}]";
public override string DeleteDefaultConstraint => "ALTER TABLE {0} DROP CONSTRAINT {2}";
public override string DropIndex => "DROP INDEX {0} ON {1}";

View File

@@ -223,6 +223,8 @@ namespace Umbraco.Core.Persistence.SqlSyntax
public abstract IEnumerable<Tuple<string, string, string, bool>> GetDefinedIndexes(IDatabase db);
public abstract string GetDefaultConstraint(IDatabase db, string tableName, string columnName);
public virtual bool DoesTableExist(IDatabase db, string tableName)
{
return false;
@@ -552,6 +554,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
public virtual string CreateConstraint => "ALTER TABLE {0} ADD CONSTRAINT {1} {2} ({3})";
public virtual string DeleteConstraint => "ALTER TABLE {0} DROP CONSTRAINT {1}";
public virtual string CreateForeignKeyConstraint => "ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4}){5}{6}";
public virtual string CreateDefaultConstraint => "ALTER TABLE {0} ADD CONSTRAINT {1} DEFAULT ({2}) FOR {3}";
public virtual string ConvertIntegerToOrderableString => "REPLACE(STR({0}, 8), SPACE(1), '0')";
public virtual string ConvertDateToOrderableString => "CONVERT(nvarchar, {0}, 102)";

View File

@@ -219,9 +219,9 @@ namespace Umbraco.Tests.Migrations
// drops *all* tables keys and indexes
var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToList();
foreach (var table in tables)
Delete.KeysAndIndexes(table, false).Do();
Delete.KeysAndIndexes(table, false, true).Do();
foreach (var table in tables)
Delete.KeysAndIndexes(table, true, false, false).Do();
Delete.KeysAndIndexes(table, true, false).Do();
}
}