mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-02-09 09:16:41 +08:00
345 lines
13 KiB
C#
345 lines
13 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using NHibernate;
|
|
using NHibernate.Dialect;
|
|
using NHibernate.SqlTypes;
|
|
using Orchard.Data.Migration.Schema;
|
|
using Orchard.Environment.Configuration;
|
|
using Orchard.Logging;
|
|
|
|
namespace Orchard.Data.Migration.Interpreters {
|
|
public class DefaultDataMigrationInterpreter : IDataMigrationInterpreter {
|
|
private readonly ShellSettings _shellSettings;
|
|
private readonly IEnumerable<ICommandInterpreter> _commandInterpreters;
|
|
private readonly ISession _session;
|
|
private readonly Dialect _dialect;
|
|
private readonly List<string> _sqlStatements;
|
|
private const char Space = ' ' ;
|
|
|
|
public DefaultDataMigrationInterpreter(ShellSettings shellSettings, ISessionLocator sessionLocator, IEnumerable<ICommandInterpreter> commandInterpreters) {
|
|
_shellSettings = shellSettings;
|
|
_commandInterpreters = commandInterpreters;
|
|
_session = sessionLocator.For(typeof(DefaultDataMigrationInterpreter));
|
|
_sqlStatements = new List<string>();
|
|
_dialect = _shellSettings.DataProvider == "SQLite" ? (Dialect) new SQLiteDialect() : new MsSql2008Dialect();
|
|
Logger = NullLogger.Instance;
|
|
}
|
|
|
|
public ILogger Logger { get; set; }
|
|
|
|
public IEnumerable<string> SqlStatements {
|
|
get { return _sqlStatements; }
|
|
}
|
|
|
|
public void Visit(ISchemaBuilderCommand command) {
|
|
var schemaCommand = command as SchemaCommand;
|
|
if (schemaCommand == null) {
|
|
return;
|
|
}
|
|
|
|
switch ( schemaCommand.Type ) {
|
|
case SchemaCommandType.CreateTable:
|
|
Visit((CreateTableCommand)schemaCommand);
|
|
break;
|
|
case SchemaCommandType.AlterTable:
|
|
Visit((AlterTableCommand)schemaCommand);
|
|
break;
|
|
case SchemaCommandType.DropTable:
|
|
Visit((DropTableCommand)schemaCommand);
|
|
break;
|
|
case SchemaCommandType.SqlStatement:
|
|
Visit((SqlStatementCommand)schemaCommand);
|
|
break;
|
|
case SchemaCommandType.CreateForeignKey:
|
|
Visit((CreateForeignKeyCommand)schemaCommand);
|
|
break;
|
|
case SchemaCommandType.DropForeignKey:
|
|
Visit((DropForeignKeyCommand)schemaCommand);
|
|
break;
|
|
}
|
|
}
|
|
|
|
public void Visit(CreateTableCommand command) {
|
|
|
|
if ( ExecuteCustomInterpreter(command) ) {
|
|
return;
|
|
}
|
|
|
|
var builder = new StringBuilder();
|
|
|
|
builder.Append(_dialect.CreateMultisetTableString)
|
|
.Append(' ')
|
|
.Append(_dialect.QuoteForTableName(_shellSettings.DataTablePrefix + command.Name))
|
|
.Append(" (");
|
|
|
|
var appendComma = false;
|
|
foreach(var createColumn in command.TableCommands.OfType<CreateColumnCommand>()) {
|
|
if(appendComma) {
|
|
builder.Append(", ");
|
|
}
|
|
appendComma = true;
|
|
|
|
Visit(builder, createColumn);
|
|
}
|
|
|
|
var primaryKeys = command.TableCommands.OfType<CreateColumnCommand>().Where(ccc => ccc.IsPrimaryKey).Select(ccc=>ccc.ColumnName);
|
|
if(primaryKeys.Any()) {
|
|
if ( appendComma ) {
|
|
builder.Append(", ");
|
|
}
|
|
|
|
builder.Append(_dialect.PrimaryKeyString)
|
|
.Append(" ( ")
|
|
.Append(String.Join(", ", primaryKeys.ToArray()))
|
|
.Append(" )");
|
|
}
|
|
|
|
builder.Append(" )");
|
|
_sqlStatements.Add(builder.ToString());
|
|
|
|
RunPendingStatements();
|
|
}
|
|
|
|
public void Visit(DropTableCommand command) {
|
|
if ( ExecuteCustomInterpreter(command) ) {
|
|
return;
|
|
}
|
|
|
|
var builder = new StringBuilder();
|
|
|
|
builder.Append(_dialect.GetDropTableString(_shellSettings.DataTablePrefix + command.Name));
|
|
_sqlStatements.Add(builder.ToString());
|
|
|
|
RunPendingStatements();
|
|
}
|
|
|
|
public void Visit(AlterTableCommand command) {
|
|
if ( ExecuteCustomInterpreter(command) ) {
|
|
return;
|
|
}
|
|
|
|
if(command.TableCommands.Count == 0) {
|
|
return;
|
|
}
|
|
|
|
// drop columns
|
|
foreach ( var dropColumn in command.TableCommands.OfType<DropColumnCommand>() ) {
|
|
var builder = new StringBuilder();
|
|
Visit(builder, dropColumn);
|
|
RunPendingStatements();
|
|
}
|
|
|
|
// add columns
|
|
foreach ( var addColumn in command.TableCommands.OfType<AddColumnCommand>() ) {
|
|
var builder = new StringBuilder();
|
|
Visit(builder, addColumn);
|
|
RunPendingStatements();
|
|
}
|
|
|
|
// alter columns
|
|
foreach ( var alterColumn in command.TableCommands.OfType<AlterColumnCommand>() ) {
|
|
var builder = new StringBuilder();
|
|
Visit(builder, alterColumn);
|
|
RunPendingStatements();
|
|
}
|
|
|
|
// add index
|
|
foreach ( var addIndex in command.TableCommands.OfType<AddIndexCommand>() ) {
|
|
var builder = new StringBuilder();
|
|
Visit(builder, addIndex);
|
|
RunPendingStatements();
|
|
}
|
|
|
|
// drop index
|
|
foreach ( var dropIndex in command.TableCommands.OfType<DropIndexCommand>() ) {
|
|
var builder = new StringBuilder();
|
|
Visit(builder, dropIndex);
|
|
RunPendingStatements();
|
|
}
|
|
|
|
}
|
|
|
|
public void Visit(StringBuilder builder, AddColumnCommand command) {
|
|
if ( ExecuteCustomInterpreter(command) ) {
|
|
return;
|
|
}
|
|
|
|
builder.AppendFormat("alter table {0} add column ", _dialect.QuoteForTableName(_shellSettings.DataTablePrefix + command.TableName));
|
|
|
|
Visit(builder, (CreateColumnCommand)command);
|
|
_sqlStatements.Add(builder.ToString());
|
|
}
|
|
|
|
public void Visit(StringBuilder builder, DropColumnCommand command) {
|
|
if ( ExecuteCustomInterpreter(command) ) {
|
|
return;
|
|
}
|
|
|
|
builder.AppendFormat("alter table {0} drop column {1}",
|
|
_dialect.QuoteForTableName(_shellSettings.DataTablePrefix + command.TableName),
|
|
_dialect.QuoteForColumnName(command.ColumnName));
|
|
_sqlStatements.Add(builder.ToString());
|
|
}
|
|
|
|
public void Visit(StringBuilder builder, AlterColumnCommand command) {
|
|
if ( ExecuteCustomInterpreter(command) ) {
|
|
return;
|
|
}
|
|
|
|
builder.AppendFormat("alter table {0} alter column {1} ",
|
|
_dialect.QuoteForTableName(_shellSettings.DataTablePrefix + command.TableName),
|
|
_dialect.QuoteForColumnName(command.TableName));
|
|
|
|
// type
|
|
if ( command.DbType != DbType.Object ) {
|
|
builder.Append(GetTypeName(command.DbType, command.Length, command.Precision, command.Scale));
|
|
}
|
|
|
|
// [default value]
|
|
if ( !string.IsNullOrEmpty(command.Default) ) {
|
|
builder.Append(" default ").Append(command.Default).Append(Space);
|
|
}
|
|
_sqlStatements.Add(builder.ToString());
|
|
}
|
|
|
|
|
|
public void Visit(StringBuilder builder, AddIndexCommand command) {
|
|
if ( ExecuteCustomInterpreter(command) ) {
|
|
return;
|
|
}
|
|
|
|
builder.AppendFormat("alter table {0} add index {1} ({2}) ",
|
|
_dialect.QuoteForTableName(_shellSettings.DataTablePrefix + command.TableName),
|
|
_dialect.QuoteForColumnName(command.IndexName),
|
|
String.Join(", ", command.ColumnNames));
|
|
|
|
_sqlStatements.Add(builder.ToString());
|
|
}
|
|
|
|
public void Visit(StringBuilder builder, DropIndexCommand command) {
|
|
if ( ExecuteCustomInterpreter(command) ) {
|
|
return;
|
|
}
|
|
|
|
builder.AppendFormat("alter table {0} drop index {1}",
|
|
_dialect.QuoteForTableName(_shellSettings.DataTablePrefix + command.TableName),
|
|
_dialect.QuoteForColumnName(command.IndexName));
|
|
_sqlStatements.Add(builder.ToString());
|
|
}
|
|
public void Visit(SqlStatementCommand command) {
|
|
if (command.Providers.Count == 0 || command.Providers.Contains(_shellSettings.DataProvider) ) {
|
|
if (ExecuteCustomInterpreter(command)) {
|
|
return;
|
|
}
|
|
_sqlStatements.Add(command.Sql);
|
|
|
|
RunPendingStatements();
|
|
}
|
|
}
|
|
|
|
public void Visit(CreateForeignKeyCommand command) {
|
|
if ( ExecuteCustomInterpreter(command) ) {
|
|
return;
|
|
}
|
|
|
|
var builder = new StringBuilder();
|
|
|
|
builder.Append("alter table ")
|
|
.Append(_dialect.QuoteForTableName(_shellSettings.DataTablePrefix + command.SrcTable));
|
|
|
|
builder.Append(_dialect.GetAddForeignKeyConstraintString(command.Name,
|
|
command.SrcColumns,
|
|
command.DestTable,
|
|
command.DestColumns,
|
|
false));
|
|
|
|
_sqlStatements.Add(builder.ToString());
|
|
|
|
RunPendingStatements();
|
|
}
|
|
|
|
public void Visit(DropForeignKeyCommand command) {
|
|
if ( ExecuteCustomInterpreter(command) ) {
|
|
return;
|
|
}
|
|
|
|
var builder = new StringBuilder();
|
|
|
|
builder.AppendFormat("alter table {0} drop constraint {1}", command.SrcTable, command.Name);
|
|
_sqlStatements.Add(builder.ToString());
|
|
|
|
RunPendingStatements();
|
|
}
|
|
|
|
private string GetTypeName(DbType dbType, int? length, byte precision, byte scale) {
|
|
return precision > 0
|
|
? _dialect.GetTypeName(new SqlType(dbType, precision, scale))
|
|
: length.HasValue
|
|
? _dialect.GetTypeName(new SqlType(dbType, length.Value))
|
|
: _dialect.GetTypeName(new SqlType(dbType));
|
|
}
|
|
|
|
private void Visit(StringBuilder builder, CreateColumnCommand command) {
|
|
if ( ExecuteCustomInterpreter(command) ) {
|
|
return;
|
|
}
|
|
|
|
// name
|
|
builder.Append(_dialect.QuoteForColumnName(command.ColumnName)).Append(Space);
|
|
|
|
// type
|
|
builder.Append(GetTypeName(command.DbType, command.Length, command.Precision, command.Scale));
|
|
|
|
// [default value]
|
|
if ( !string.IsNullOrEmpty(command.Default) ) {
|
|
builder.Append(" default ").Append(command.Default).Append(Space);
|
|
}
|
|
|
|
// nullable
|
|
builder.Append(command.IsNotNull
|
|
? " not null"
|
|
: !command.IsPrimaryKey && !command.IsUnique
|
|
? _dialect.NullColumnString
|
|
: string.Empty);
|
|
|
|
// append unique if handled, otherwise at the end of the satement
|
|
if ( command.IsUnique && _dialect.SupportsUnique ) {
|
|
builder.Append(" unique");
|
|
}
|
|
}
|
|
|
|
private void RunPendingStatements() {
|
|
|
|
var connection = _session.Connection;
|
|
|
|
foreach ( var sqlStatement in _sqlStatements ) {
|
|
Logger.Debug(sqlStatement);
|
|
using ( var command = connection.CreateCommand() ) {
|
|
command.CommandText = sqlStatement;
|
|
command.ExecuteNonQuery();
|
|
}
|
|
}
|
|
|
|
_sqlStatements.Clear();
|
|
}
|
|
|
|
private bool ExecuteCustomInterpreter<T>(T command) where T : ISchemaBuilderCommand {
|
|
var interpreter = _commandInterpreters
|
|
.Where(ici => ici.DataProvider == _shellSettings.DataProvider)
|
|
.OfType<ICommandInterpreter<T>>()
|
|
.FirstOrDefault();
|
|
|
|
if ( interpreter != null ) {
|
|
_sqlStatements.AddRange(interpreter.CreateStatements(command));
|
|
RunPendingStatements();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|