Merge
This commit is contained in:
@@ -16,6 +16,8 @@ echo This file is only here so that the containing folder will be included in th
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\media\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\scripts\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\usercontrols\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\Views\Partials\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\Views\MacroPartials\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\xslt\dummy.txt
|
||||
|
||||
..\src\.nuget\NuGet.exe pack NuSpecs\UmbracoCms.Core.nuspec -Version %version%
|
||||
|
||||
@@ -9,6 +9,7 @@ using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Migrations;
|
||||
using Umbraco.Core.Persistence.Migrations.Initial;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core
|
||||
@@ -25,8 +26,9 @@ namespace Umbraco.Core
|
||||
private bool _configured;
|
||||
private string _connectionString;
|
||||
private string _providerName;
|
||||
private DatabaseSchemaResult _result;
|
||||
|
||||
internal DatabaseContext(IDatabaseFactory factory)
|
||||
internal DatabaseContext(IDatabaseFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
@@ -242,20 +244,40 @@ namespace Umbraco.Core
|
||||
|
||||
}
|
||||
|
||||
if (providerName.StartsWith("MySql"))
|
||||
Initialize(providerName);
|
||||
}
|
||||
else if (ConfigurationManager.AppSettings.ContainsKey(GlobalSettings.UmbracoConnectionName) && string.IsNullOrEmpty(ConfigurationManager.AppSettings[GlobalSettings.UmbracoConnectionName]) == false)
|
||||
{
|
||||
//A valid connectionstring does not exist, but the legacy appSettings key was found, so we'll reconfigure the conn.string.
|
||||
var legacyConnString = ConfigurationManager.AppSettings[GlobalSettings.UmbracoConnectionName];
|
||||
if (legacyConnString.ToLowerInvariant().Contains("sqlce4umbraco"))
|
||||
{
|
||||
SyntaxConfig.SqlSyntaxProvider = MySqlSyntax.Provider;
|
||||
ConfigureDatabaseConnection();
|
||||
}
|
||||
else if (providerName.Contains("SqlServerCe"))
|
||||
else if (legacyConnString.ToLowerInvariant().Contains("database.windows.net") &&
|
||||
legacyConnString.ToLowerInvariant().Contains("tcp:"))
|
||||
{
|
||||
SyntaxConfig.SqlSyntaxProvider = SqlCeSyntax.Provider;
|
||||
//Must be sql azure
|
||||
SaveConnectionString(legacyConnString, "System.Data.SqlClient");
|
||||
Initialize("System.Data.SqlClient");
|
||||
}
|
||||
else if (legacyConnString.ToLowerInvariant().Contains("Uid") &&
|
||||
legacyConnString.ToLowerInvariant().Contains("Pwd") &&
|
||||
legacyConnString.ToLowerInvariant().Contains("Server"))
|
||||
{
|
||||
//Must be MySql
|
||||
SaveConnectionString(legacyConnString, "MySql.Data.MySqlClient");
|
||||
Initialize("MySql.Data.MySqlClient");
|
||||
}
|
||||
else
|
||||
{
|
||||
SyntaxConfig.SqlSyntaxProvider = SqlServerSyntax.Provider;
|
||||
//Must be sql
|
||||
SaveConnectionString(legacyConnString, "System.Data.SqlClient");
|
||||
Initialize("System.Data.SqlClient");
|
||||
}
|
||||
|
||||
_configured = true;
|
||||
//Remove the legacy connection string, so we don't end up in a loop if something goes wrong.
|
||||
GlobalSettings.RemoveSetting(GlobalSettings.UmbracoConnectionName);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -277,38 +299,81 @@ namespace Umbraco.Core
|
||||
{
|
||||
SyntaxConfig.SqlSyntaxProvider = SqlServerSyntax.Provider;
|
||||
}
|
||||
|
||||
|
||||
_providerName = providerName;
|
||||
_configured = true;
|
||||
}
|
||||
|
||||
internal DatabaseSchemaResult ValidateDatabaseSchema()
|
||||
{
|
||||
if (_configured == false || (string.IsNullOrEmpty(_connectionString) || string.IsNullOrEmpty(ProviderName)))
|
||||
return new DatabaseSchemaResult();
|
||||
|
||||
if (_result == null)
|
||||
{
|
||||
var database = new UmbracoDatabase(_connectionString, ProviderName);
|
||||
var dbSchema = new DatabaseSchemaCreation(database);
|
||||
_result = dbSchema.ValidateSchema();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
internal Result CreateDatabaseSchemaAndDataOrUpgrade()
|
||||
{
|
||||
if (_configured == false || (string.IsNullOrEmpty(_connectionString) || string.IsNullOrEmpty(ProviderName)))
|
||||
{
|
||||
return new Result{Message = "Database configuration is invalid", Success = false, Percentage = "10"};
|
||||
return new Result
|
||||
{
|
||||
Message =
|
||||
"Database configuration is invalid. Please check that the entered database exists and that the provided username and password has write access to the database.",
|
||||
Success = false,
|
||||
Percentage = "10"
|
||||
};
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var database = new UmbracoDatabase(_connectionString, ProviderName);
|
||||
//If Configuration Status is empty its a new install - otherwise upgrade the existing
|
||||
if (string.IsNullOrEmpty(GlobalSettings.ConfigurationStatus))
|
||||
var schemaResult = ValidateDatabaseSchema();
|
||||
var installedVersion = schemaResult.DetermineInstalledVersion();
|
||||
string message;
|
||||
|
||||
//If Configuration Status is empty and the determined version is "empty" its a new install - otherwise upgrade the existing
|
||||
if (string.IsNullOrEmpty(GlobalSettings.ConfigurationStatus) && installedVersion.Equals(new Version(0, 0, 0)))
|
||||
{
|
||||
database.CreateDatabaseSchema();
|
||||
message = "Installation completed!";
|
||||
}
|
||||
else
|
||||
{
|
||||
var configuredVersion = new Version(GlobalSettings.ConfigurationStatus);
|
||||
var configuredVersion = string.IsNullOrEmpty(GlobalSettings.ConfigurationStatus)
|
||||
? installedVersion
|
||||
: new Version(GlobalSettings.ConfigurationStatus);
|
||||
var targetVersion = UmbracoVersion.Current;
|
||||
var runner = new MigrationRunner(configuredVersion, targetVersion, GlobalSettings.UmbracoMigrationName);
|
||||
var upgraded = runner.Execute(database, true);
|
||||
message = "Upgrade completed!";
|
||||
}
|
||||
|
||||
return new Result { Message = "Installation completed!", Success = true, Percentage = "100" };
|
||||
return new Result { Message = message, Success = true, Percentage = "100" };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new Result { Message = ex.Message, Success = false, Percentage = "90" };
|
||||
LogHelper.Info<DatabaseContext>("Database configuration failed with the following error and stack trace: " + ex.Message + "\n" + ex.StackTrace);
|
||||
|
||||
if (_result != null)
|
||||
{
|
||||
LogHelper.Info<DatabaseContext>("The database schema validation produced the following summary: \n" + _result.GetSummary());
|
||||
}
|
||||
|
||||
return new Result
|
||||
{
|
||||
Message =
|
||||
"The database configuration failed with the following message: " + ex.Message +
|
||||
"\n Please check log file for addtional information (can be found in '/App_Data/Logs/UmbracoTraceLog.txt')",
|
||||
Success = false,
|
||||
Percentage = "90"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,29 +3,34 @@
|
||||
public interface IUmbracoEntity : IAggregateRoot
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the Id of the Parent entity
|
||||
/// Profile of the user who created this Entity
|
||||
/// </summary>
|
||||
int ParentId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the sort order of the Entity
|
||||
/// </summary>
|
||||
int SortOrder { get; set; }
|
||||
int CreatorId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the level of the Entity
|
||||
/// </summary>
|
||||
int Level { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets the Name of the Entity
|
||||
/// </summary>
|
||||
string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Id of the Parent Entity
|
||||
/// </summary>
|
||||
int ParentId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path to the Entity
|
||||
/// </summary>
|
||||
string Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Profile of the user who created this Entity
|
||||
/// Gets or sets the sort order of the Entity
|
||||
/// </summary>
|
||||
int CreatorId { get; set; }
|
||||
int SortOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Boolean indicating whether this Entity is Trashed or not.
|
||||
|
||||
@@ -10,11 +10,6 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
public interface IContentBase : IUmbracoEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or Sets the Name of the Content
|
||||
/// </summary>
|
||||
string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Integer Id of the default ContentType
|
||||
/// </summary>
|
||||
|
||||
@@ -15,11 +15,6 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
string Alias { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets the Name of the ContentType
|
||||
/// </summary>
|
||||
string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets the Description for the ContentType
|
||||
/// </summary>
|
||||
|
||||
@@ -5,11 +5,6 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
public interface IDataTypeDefinition : IUmbracoEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the current entity
|
||||
/// </summary>
|
||||
string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id of the DataType control
|
||||
/// </summary>
|
||||
|
||||
@@ -84,10 +84,14 @@ namespace Umbraco.Core.Persistence.DatabaseModelDefinitions
|
||||
var primaryKeyColumnAttribute = propertyInfo.FirstAttribute<PrimaryKeyColumnAttribute>();
|
||||
if (primaryKeyColumnAttribute != null)
|
||||
{
|
||||
string primaryKeyName = string.IsNullOrEmpty(primaryKeyColumnAttribute.Name)
|
||||
? string.Format("PK_{0}", tableName)
|
||||
: primaryKeyColumnAttribute.Name;
|
||||
|
||||
definition.IsPrimaryKey = true;
|
||||
definition.IsIdentity = primaryKeyColumnAttribute.AutoIncrement;
|
||||
definition.IsIndexed = primaryKeyColumnAttribute.Clustered;
|
||||
definition.PrimaryKeyName = primaryKeyColumnAttribute.Name ?? string.Empty;
|
||||
definition.PrimaryKeyName = primaryKeyName;
|
||||
definition.PrimaryKeyColumns = primaryKeyColumnAttribute.OnColumns ?? string.Empty;
|
||||
definition.Seeding = primaryKeyColumnAttribute.IdentitySeed;
|
||||
}
|
||||
@@ -120,9 +124,13 @@ namespace Umbraco.Core.Persistence.DatabaseModelDefinitions
|
||||
? referencedPrimaryKey.Value
|
||||
: attribute.Column;
|
||||
|
||||
string foreignKeyName = string.IsNullOrEmpty(attribute.Name)
|
||||
? string.Format("FK_{0}_{1}_{2}", tableName, referencedTable.Value, referencedColumn)
|
||||
: attribute.Name;
|
||||
|
||||
var definition = new ForeignKeyDefinition
|
||||
{
|
||||
Name = attribute.Name,
|
||||
Name = foreignKeyName,
|
||||
ForeignTable = tableName,
|
||||
PrimaryTable = referencedTable.Value
|
||||
};
|
||||
@@ -134,9 +142,13 @@ namespace Umbraco.Core.Persistence.DatabaseModelDefinitions
|
||||
|
||||
public static IndexDefinition GetIndexDefinition(Type modelType, PropertyInfo propertyInfo, IndexAttribute attribute, string columnName, string tableName)
|
||||
{
|
||||
string indexName = string.IsNullOrEmpty(attribute.Name)
|
||||
? string.Format("IX_{0}_{1}", tableName, columnName)
|
||||
: attribute.Name;
|
||||
|
||||
var definition = new IndexDefinition
|
||||
{
|
||||
Name = attribute.Name,
|
||||
Name = indexName,
|
||||
IndexType = attribute.IndexType,
|
||||
ColumnName = columnName,
|
||||
TableName = tableName,
|
||||
|
||||
@@ -3,6 +3,8 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
{
|
||||
@@ -95,19 +97,102 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
|
||||
foreach (var item in OrderedTables.OrderBy(x => x.Key))
|
||||
{
|
||||
var tableNameAttribute = item.Value.FirstAttribute<TableNameAttribute>();
|
||||
if (tableNameAttribute != null)
|
||||
var tableDefinition = DefinitionFactory.GetTableDefinition(item.Value);
|
||||
result.TableDefinitions.Add(tableDefinition);
|
||||
}
|
||||
|
||||
//Check tables in configured database against tables in schema
|
||||
var tablesInDatabase = SyntaxConfig.SqlSyntaxProvider.GetTablesInSchema(_database).ToList();
|
||||
var tablesInSchema = result.TableDefinitions.Select(x => x.Name).ToList();
|
||||
//Add valid and invalid table differences to the result object
|
||||
var validTableDifferences = tablesInDatabase.Intersect(tablesInSchema);
|
||||
foreach (var tableName in validTableDifferences)
|
||||
{
|
||||
result.ValidTables.Add(tableName);
|
||||
}
|
||||
var invalidTableDifferences = tablesInDatabase.Except(tablesInSchema);
|
||||
foreach (var tableName in invalidTableDifferences)
|
||||
{
|
||||
result.Errors.Add(new Tuple<string, string>("Table", tableName));
|
||||
}
|
||||
|
||||
//Check columns in configured database against columns in schema
|
||||
var columnsInDatabase = SyntaxConfig.SqlSyntaxProvider.GetColumnsInSchema(_database);
|
||||
var columnsPerTableInDatabase = columnsInDatabase.Select(x => string.Concat(x.TableName, ",", x.ColumnName)).ToList();
|
||||
var columnsPerTableInSchema = result.TableDefinitions.SelectMany(x => x.Columns.Select(y => string.Concat(y.TableName, ",", y.Name))).ToList();
|
||||
//Add valid and invalid column differences to the result object
|
||||
var validColumnDifferences = columnsPerTableInDatabase.Intersect(columnsPerTableInSchema);
|
||||
foreach (var column in validColumnDifferences)
|
||||
{
|
||||
result.ValidColumns.Add(column);
|
||||
}
|
||||
var invalidColumnDifferences = columnsPerTableInDatabase.Except(columnsPerTableInSchema);
|
||||
foreach (var column in invalidColumnDifferences)
|
||||
{
|
||||
result.Errors.Add(new Tuple<string, string>("Column", column));
|
||||
}
|
||||
|
||||
//MySql doesn't conform to the "normal" naming of constraints, so there is currently no point in doing these checks.
|
||||
//NOTE: At a later point we do other checks for MySql, but ideally it should be necessary to do special checks for different providers.
|
||||
if (SyntaxConfig.SqlSyntaxProvider is MySqlSyntaxProvider)
|
||||
return result;
|
||||
|
||||
//Check constraints in configured database against constraints in schema
|
||||
var constraintsInDatabase = SyntaxConfig.SqlSyntaxProvider.GetConstraintsPerColumn(_database).DistinctBy(x => x.Item3).ToList();
|
||||
var foreignKeysInDatabase = constraintsInDatabase.Where(x => x.Item3.StartsWith("FK_")).Select(x => x.Item3).ToList();
|
||||
var primaryKeysInDatabase = constraintsInDatabase.Where(x => x.Item3.StartsWith("PK_")).Select(x => x.Item3).ToList();
|
||||
var indexesInDatabase = constraintsInDatabase.Where(x => x.Item3.StartsWith("IX_")).Select(x => x.Item3).ToList();
|
||||
var unknownConstraintsInDatabase =
|
||||
constraintsInDatabase.Where(
|
||||
x =>
|
||||
x.Item3.StartsWith("FK_") == false && x.Item3.StartsWith("PK_") == false &&
|
||||
x.Item3.StartsWith("IX_") == false).Select(x => x.Item3).ToList();
|
||||
var foreignKeysInSchema = result.TableDefinitions.SelectMany(x => x.ForeignKeys.Select(y => y.Name)).ToList();
|
||||
var primaryKeysInSchema = result.TableDefinitions.SelectMany(x => x.Columns.Select(y => y.PrimaryKeyName)).ToList();
|
||||
var indexesInSchema = result.TableDefinitions.SelectMany(x => x.Indexes.Select(y => y.Name)).ToList();
|
||||
//Add valid and invalid foreign key differences to the result object
|
||||
foreach (var unknown in unknownConstraintsInDatabase)
|
||||
{
|
||||
if (foreignKeysInSchema.Contains(unknown) || primaryKeysInSchema.Contains(unknown) || indexesInSchema.Contains(unknown))
|
||||
{
|
||||
var tableExist = _database.TableExist(tableNameAttribute.Value);
|
||||
if (tableExist)
|
||||
{
|
||||
result.Successes.Add(tableNameAttribute.Value, "Table exists");
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Errors.Add(tableNameAttribute.Value, "Table does not exist");
|
||||
}
|
||||
result.ValidConstraints.Add(unknown);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Errors.Add(new Tuple<string, string>("Unknown", unknown));
|
||||
}
|
||||
}
|
||||
var validForeignKeyDifferences = foreignKeysInDatabase.Intersect(foreignKeysInSchema);
|
||||
foreach (var foreignKey in validForeignKeyDifferences)
|
||||
{
|
||||
result.ValidConstraints.Add(foreignKey);
|
||||
}
|
||||
var invalidForeignKeyDifferences = foreignKeysInDatabase.Except(foreignKeysInSchema);
|
||||
foreach (var foreignKey in invalidForeignKeyDifferences)
|
||||
{
|
||||
result.Errors.Add(new Tuple<string, string>("Constraint", foreignKey));
|
||||
}
|
||||
//Add valid and invalid primary key differences to the result object
|
||||
var validPrimaryKeyDifferences = primaryKeysInDatabase.Intersect(primaryKeysInSchema);
|
||||
foreach (var primaryKey in validPrimaryKeyDifferences)
|
||||
{
|
||||
result.ValidConstraints.Add(primaryKey);
|
||||
}
|
||||
var invalidPrimaryKeyDifferences = primaryKeysInDatabase.Except(primaryKeysInSchema);
|
||||
foreach (var primaryKey in invalidPrimaryKeyDifferences)
|
||||
{
|
||||
result.Errors.Add(new Tuple<string, string>("Constraint", primaryKey));
|
||||
}
|
||||
//Add valid and invalid index differences to the result object
|
||||
var validIndexDifferences = indexesInDatabase.Intersect(indexesInSchema);
|
||||
foreach (var index in validIndexDifferences)
|
||||
{
|
||||
result.ValidConstraints.Add(index);
|
||||
}
|
||||
var invalidIndexDifferences = indexesInDatabase.Except(indexesInSchema);
|
||||
foreach (var index in invalidIndexDifferences)
|
||||
{
|
||||
result.Errors.Add(new Tuple<string, string>("Constraint", index));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
{
|
||||
@@ -6,12 +12,109 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
{
|
||||
public DatabaseSchemaResult()
|
||||
{
|
||||
Errors = new Dictionary<string, string>();
|
||||
Successes = new Dictionary<string, string>();
|
||||
Errors = new List<Tuple<string, string>>();
|
||||
TableDefinitions = new List<TableDefinition>();
|
||||
ValidTables = new List<string>();
|
||||
ValidColumns = new List<string>();
|
||||
ValidConstraints = new List<string>();
|
||||
}
|
||||
|
||||
public IDictionary<string, string> Errors { get; set; }
|
||||
public List<Tuple<string, string>> Errors { get; set; }
|
||||
|
||||
public IDictionary<string, string> Successes { get; set; }
|
||||
public List<TableDefinition> TableDefinitions { get; set; }
|
||||
|
||||
public List<string> ValidTables { get; set; }
|
||||
|
||||
public List<string> ValidColumns { get; set; }
|
||||
|
||||
public List<string> ValidConstraints { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines the version of the currently installed database.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="Version"/> with Major and Minor values for
|
||||
/// non-empty database, otherwise "0.0.0" for empty databases.
|
||||
/// </returns>
|
||||
public Version DetermineInstalledVersion()
|
||||
{
|
||||
//If (ValidTables.Count == 0) database is empty and we return -> new Version(0, 0, 0);
|
||||
if(ValidTables.Count == 0)
|
||||
return new Version(0, 0, 0);
|
||||
|
||||
//If Errors is empty then we're at current version
|
||||
if (Errors.Any() == false)
|
||||
return UmbracoVersion.Current;
|
||||
|
||||
//If Errors contains umbracoApp or umbracoAppTree its pre-6.0.0 -> new Version(4, 10, 0);
|
||||
if (
|
||||
Errors.Any(
|
||||
x => x.Item1.Equals("Table") && (x.Item2.Equals("umbracoApp") || x.Item2.Equals("umbracoAppTree"))))
|
||||
{
|
||||
//If Errors contains umbracoUser2app or umbracoAppTree foreignkey to umbracoApp exists its pre-4.8.0 -> new Version(4, 7, 0);
|
||||
if (
|
||||
Errors.Any(
|
||||
x =>
|
||||
x.Item1.Equals("Constraint") &&
|
||||
(x.Item2.Contains("umbracoUser2app_umbracoApp") || x.Item2.Contains("umbracoAppTree_umbracoApp"))))
|
||||
{
|
||||
return new Version(4, 7, 0);
|
||||
}
|
||||
|
||||
return new Version(4, 9, 0);
|
||||
}
|
||||
|
||||
return new Version(0, 0, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a summary of the schema validation result
|
||||
/// </summary>
|
||||
/// <returns>A string containing a human readable string with a summary message</returns>
|
||||
public string GetSummary()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
if (Errors.Any() == false)
|
||||
{
|
||||
sb.AppendLine("The database schema validation didn't find any errors.");
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
//Table error summary
|
||||
if (Errors.Any(x => x.Item1.Equals("Table")))
|
||||
{
|
||||
sb.AppendLine("The following tables were found in the database, but are not in the current schema:");
|
||||
sb.AppendLine(string.Join(",", Errors.Where(x => x.Item1.Equals("Table")).Select(x => x.Item2)));
|
||||
sb.AppendLine(" ");
|
||||
}
|
||||
//Column error summary
|
||||
if (Errors.Any(x => x.Item1.Equals("Column")))
|
||||
{
|
||||
sb.AppendLine("The following columns were found in the database, but are not in the current schema:");
|
||||
sb.AppendLine(string.Join(",", Errors.Where(x => x.Item1.Equals("Column")).Select(x => x.Item2)));
|
||||
sb.AppendLine(" ");
|
||||
}
|
||||
//Constraint error summary
|
||||
if (Errors.Any(x => x.Item1.Equals("Constraint")))
|
||||
{
|
||||
sb.AppendLine("The following constraints (Primary Keys, Foreign Keys and Indexes) were found in the database, but are not in the current schema:");
|
||||
sb.AppendLine(string.Join(",", Errors.Where(x => x.Item1.Equals("Constraint")).Select(x => x.Item2)));
|
||||
sb.AppendLine(" ");
|
||||
}
|
||||
//Unknown constraint error summary
|
||||
if (Errors.Any(x => x.Item1.Equals("Unknown")))
|
||||
{
|
||||
sb.AppendLine("The following unknown constraints (Primary Keys, Foreign Keys and Indexes) were found in the database, but are not in the current schema:");
|
||||
sb.AppendLine(string.Join(",", Errors.Where(x => x.Item1.Equals("Unknown")).Select(x => x.Item2)));
|
||||
sb.AppendLine(" ");
|
||||
}
|
||||
|
||||
if (SyntaxConfig.SqlSyntaxProvider is MySqlSyntaxProvider)
|
||||
{
|
||||
sb.AppendLine("Please note that the constraints could not be validated because the current dataprovider is MySql.");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
public class ColumnInfo
|
||||
{
|
||||
public ColumnInfo(string tableName, string columnName, int ordinal, string columnDefault, string isNullable, string dataType)
|
||||
{
|
||||
TableName = tableName;
|
||||
ColumnName = columnName;
|
||||
Ordinal = ordinal;
|
||||
ColumnDefault = columnDefault;
|
||||
IsNullable = isNullable.Equals("YES");
|
||||
DataType = dataType;
|
||||
}
|
||||
|
||||
public ColumnInfo(string tableName, string columnName, int ordinal, string isNullable, string dataType)
|
||||
{
|
||||
TableName = tableName;
|
||||
ColumnName = columnName;
|
||||
Ordinal = ordinal;
|
||||
IsNullable = isNullable.Equals("YES");
|
||||
DataType = dataType;
|
||||
}
|
||||
|
||||
public string TableName { get; set; }
|
||||
public string ColumnName { get; set; }
|
||||
public int Ordinal { get; set; }
|
||||
public string ColumnDefault { get; set; }
|
||||
public bool IsNullable { get; set; }
|
||||
public string DataType { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
@@ -47,5 +48,9 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
string FormatTableRename(string oldName, string newName);
|
||||
bool SupportsClustered();
|
||||
bool SupportsIdentityInsert();
|
||||
IEnumerable<string> GetTablesInSchema(Database db);
|
||||
IEnumerable<ColumnInfo> GetColumnsInSchema(Database db);
|
||||
IEnumerable<Tuple<string, string>> GetConstraintsPerTable(Database db);
|
||||
IEnumerable<Tuple<string, string, string>> GetConstraintsPerColumn(Database db);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
@@ -39,6 +40,90 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
DefaultValueFormat = "DEFAULT '{0}'";
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetTablesInSchema(Database db)
|
||||
{
|
||||
List<string> list;
|
||||
try
|
||||
{
|
||||
db.OpenSharedConnection();
|
||||
var items =
|
||||
db.Fetch<dynamic>(
|
||||
"SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = @TableSchema",
|
||||
new {TableSchema = db.Connection.Database});
|
||||
list = items.Select(x => x.TABLE_NAME).Cast<string>().ToList();
|
||||
}
|
||||
finally
|
||||
{
|
||||
db.CloseSharedConnection();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public override IEnumerable<ColumnInfo> GetColumnsInSchema(Database db)
|
||||
{
|
||||
List<ColumnInfo> list;
|
||||
try
|
||||
{
|
||||
db.OpenSharedConnection();
|
||||
var items =
|
||||
db.Fetch<dynamic>(
|
||||
"SELECT TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @TableSchema",
|
||||
new {TableSchema = db.Connection.Database});
|
||||
list =
|
||||
items.Select(
|
||||
item =>
|
||||
new ColumnInfo(item.TABLE_NAME, item.COLUMN_NAME, item.ORDINAL_POSITION, item.COLUMN_DEFAULT,
|
||||
item.IS_NULLABLE, item.DATA_TYPE)).ToList();
|
||||
}
|
||||
finally
|
||||
{
|
||||
db.CloseSharedConnection();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public override IEnumerable<Tuple<string, string>> GetConstraintsPerTable(Database db)
|
||||
{
|
||||
List<Tuple<string, string>> list;
|
||||
try
|
||||
{
|
||||
//Does not include indexes and constraints are named differently
|
||||
var items =
|
||||
db.Fetch<dynamic>(
|
||||
"SELECT TABLE_NAME, CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA = @TableSchema",
|
||||
new {TableSchema = db.Connection.Database});
|
||||
list = items.Select(item => new Tuple<string, string>(item.TABLE_NAME, item.CONSTRAINT_NAME)).ToList();
|
||||
}
|
||||
finally
|
||||
{
|
||||
db.CloseSharedConnection();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public override IEnumerable<Tuple<string, string, string>> GetConstraintsPerColumn(Database db)
|
||||
{
|
||||
List<Tuple<string, string, string>> list;
|
||||
try
|
||||
{
|
||||
//Does not include indexes and constraints are named differently
|
||||
var items =
|
||||
db.Fetch<dynamic>(
|
||||
"SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = @TableSchema",
|
||||
new {TableSchema = db.Connection.Database});
|
||||
list =
|
||||
items.Select(
|
||||
item =>
|
||||
new Tuple<string, string, string>(item.TABLE_NAME, item.COLUMN_NAME, item.CONSTRAINT_NAME))
|
||||
.ToList();
|
||||
}
|
||||
finally
|
||||
{
|
||||
db.CloseSharedConnection();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public override bool DoesTableExist(Database db, string tableName)
|
||||
{
|
||||
long result;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
@@ -112,6 +113,50 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
columns);
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetTablesInSchema(Database db)
|
||||
{
|
||||
var items = db.Fetch<dynamic>("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES");
|
||||
return items.Select(x => x.TABLE_NAME).Cast<string>().ToList();
|
||||
}
|
||||
|
||||
public override IEnumerable<ColumnInfo> GetColumnsInSchema(Database db)
|
||||
{
|
||||
var items = db.Fetch<dynamic>("SELECT TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS");
|
||||
return
|
||||
items.Select(
|
||||
item =>
|
||||
new ColumnInfo(item.TABLE_NAME, item.COLUMN_NAME, item.ORDINAL_POSITION, item.COLUMN_DEFAULT,
|
||||
item.IS_NULLABLE, item.DATA_TYPE)).ToList();
|
||||
}
|
||||
|
||||
public override IEnumerable<Tuple<string, string>> GetConstraintsPerTable(Database db)
|
||||
{
|
||||
var items = db.Fetch<dynamic>("SELECT TABLE_NAME, CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS");
|
||||
var indexItems = db.Fetch<dynamic>("SELECT TABLE_NAME, INDEX_NAME FROM INFORMATION_SCHEMA.INDEXES");
|
||||
return
|
||||
items.Select(item => new Tuple<string, string>(item.TABLE_NAME, item.CONSTRAINT_NAME))
|
||||
.Union(
|
||||
indexItems.Select(
|
||||
indexItem => new Tuple<string, string>(indexItem.TABLE_NAME, indexItem.INDEX_NAME)))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public override IEnumerable<Tuple<string, string, string>> GetConstraintsPerColumn(Database db)
|
||||
{
|
||||
var items =
|
||||
db.Fetch<dynamic>(
|
||||
"SELECT CONSTRAINT_NAME, TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE");
|
||||
var indexItems = db.Fetch<dynamic>("SELECT INDEX_NAME, TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.INDEXES");
|
||||
return
|
||||
items.Select(
|
||||
item => new Tuple<string, string, string>(item.TABLE_NAME, item.COLUMN_NAME, item.CONSTRAINT_NAME))
|
||||
.Union(
|
||||
indexItems.Select(
|
||||
indexItem =>
|
||||
new Tuple<string, string, string>(indexItem.TABLE_NAME, indexItem.COLUMN_NAME,
|
||||
indexItem.INDEX_NAME))).ToList();
|
||||
}
|
||||
|
||||
public override bool DoesTableExist(Database db, string tableName)
|
||||
{
|
||||
var result =
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
@@ -49,6 +52,38 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
return string.Format("[{0}]", name);
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetTablesInSchema(Database db)
|
||||
{
|
||||
var items = db.Fetch<dynamic>("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES");
|
||||
return items.Select(x => x.TABLE_NAME).Cast<string>().ToList();
|
||||
}
|
||||
|
||||
public override IEnumerable<ColumnInfo> GetColumnsInSchema(Database db)
|
||||
{
|
||||
var items = db.Fetch<dynamic>("SELECT TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS");
|
||||
return
|
||||
items.Select(
|
||||
item =>
|
||||
new ColumnInfo(item.TABLE_NAME, item.COLUMN_NAME, item.ORDINAL_POSITION, item.COLUMN_DEFAULT,
|
||||
item.IS_NULLABLE, item.DATA_TYPE)).ToList();
|
||||
}
|
||||
|
||||
public override IEnumerable<Tuple<string, string>> GetConstraintsPerTable(Database db)
|
||||
{
|
||||
var items =
|
||||
db.Fetch<dynamic>(
|
||||
"SELECT TABLE_NAME, CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE");
|
||||
return items.Select(item => new Tuple<string, string>(item.TABLE_NAME, item.CONSTRAINT_NAME)).ToList();
|
||||
}
|
||||
|
||||
public override IEnumerable<Tuple<string, string, string>> GetConstraintsPerColumn(Database db)
|
||||
{
|
||||
var items =
|
||||
db.Fetch<dynamic>(
|
||||
"SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE");
|
||||
return items.Select(item => new Tuple<string, string, string>(item.TABLE_NAME, item.COLUMN_NAME, item.CONSTRAINT_NAME)).ToList();
|
||||
}
|
||||
|
||||
public override bool DoesTableExist(Database db, string tableName)
|
||||
{
|
||||
var result =
|
||||
|
||||
@@ -151,6 +151,26 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
return "NVARCHAR";
|
||||
}
|
||||
|
||||
public virtual IEnumerable<string> GetTablesInSchema(Database db)
|
||||
{
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
public virtual IEnumerable<ColumnInfo> GetColumnsInSchema(Database db)
|
||||
{
|
||||
return new List<ColumnInfo>();
|
||||
}
|
||||
|
||||
public virtual IEnumerable<Tuple<string, string>> GetConstraintsPerTable(Database db)
|
||||
{
|
||||
return new List<Tuple<string, string>>();
|
||||
}
|
||||
|
||||
public virtual IEnumerable<Tuple<string, string, string>> GetConstraintsPerColumn(Database db)
|
||||
{
|
||||
return new List<Tuple<string, string, string>>();
|
||||
}
|
||||
|
||||
public virtual bool DoesTableExist(Database db, string tableName)
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -1228,13 +1228,12 @@ namespace Umbraco.Core.Services
|
||||
_publishingStrategy.PublishingFinalized(content);
|
||||
|
||||
//We need to check if children and their publish state to ensure that we republish content that was previously published
|
||||
if (HasChildren(content.Id))
|
||||
if (omitCacheRefresh == false && HasChildren(content.Id))
|
||||
{
|
||||
var children = GetDescendants(content);
|
||||
var shouldBeRepublished = children.Where(child => HasPublishedVersion(child.Id));
|
||||
|
||||
if (omitCacheRefresh == false)
|
||||
_publishingStrategy.PublishingFinalized(shouldBeRepublished, false);
|
||||
_publishingStrategy.PublishingFinalized(shouldBeRepublished, false);
|
||||
}
|
||||
|
||||
Audit.Add(AuditTypes.Publish, "Save and Publish performed by user", userId, content.Id);
|
||||
|
||||
@@ -439,6 +439,7 @@
|
||||
<Compile Include="Persistence\Repositories\VersionableRepositoryBase.cs" />
|
||||
<Compile Include="Persistence\RepositoryFactory.cs" />
|
||||
<Compile Include="Persistence\RepositoryResolver.cs" />
|
||||
<Compile Include="Persistence\SqlSyntax\ColumnInfo.cs" />
|
||||
<Compile Include="Persistence\SqlSyntax\DbTypes.cs" />
|
||||
<Compile Include="Persistence\SqlSyntax\ISqlSyntaxProvider.cs" />
|
||||
<Compile Include="Persistence\SqlSyntax\MySqlSyntaxProvider.cs" />
|
||||
|
||||
@@ -76,6 +76,8 @@
|
||||
<DbProviderFactories>
|
||||
<remove invariant="System.Data.SqlServerCe.4.0"/>
|
||||
<add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91" />
|
||||
<remove invariant="MySql.Data.MySqlClient"/>
|
||||
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.6.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
|
||||
</DbProviderFactories>
|
||||
</system.data>
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ using Umbraco.Core.Persistence.Migrations;
|
||||
using Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Web.Strategies.Migrations;
|
||||
using GlobalSettings = Umbraco.Core.Configuration.GlobalSettings;
|
||||
|
||||
namespace Umbraco.Tests.Migrations.Upgrades
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Data.SqlServerCe;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using NUnit.Framework;
|
||||
using SQLCE4Umbraco;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Migrations.Initial;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
|
||||
namespace Umbraco.Tests.Migrations.Upgrades
|
||||
{
|
||||
[TestFixture]
|
||||
public class ValidateOlderSchemaTest
|
||||
{
|
||||
/// <summary>Regular expression that finds multiline block comments.</summary>
|
||||
private static readonly Regex FindComments = new Regex(@"\/\*.*?\*\/", RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
|
||||
[Test]
|
||||
public virtual void DatabaseSchemaCreation_Returns_DatabaseSchemaResult_Where_DetermineInstalledVersion_Is_4_7_0()
|
||||
{
|
||||
// Arrange
|
||||
var db = GetConfiguredDatabase();
|
||||
var schema = new DatabaseSchemaCreation(db);
|
||||
|
||||
//Create db schema and data from old Total.sql file for Sql Ce
|
||||
string statements = GetDatabaseSpecificSqlScript();
|
||||
// replace block comments by whitespace
|
||||
statements = FindComments.Replace(statements, " ");
|
||||
// execute all non-empty statements
|
||||
foreach (string statement in statements.Split(";".ToCharArray()))
|
||||
{
|
||||
string rawStatement = statement.Replace("GO", "").Trim();
|
||||
if (rawStatement.Length > 0)
|
||||
db.Execute(new Sql(rawStatement));
|
||||
}
|
||||
|
||||
// Act
|
||||
var result = schema.ValidateSchema();
|
||||
|
||||
// Assert
|
||||
var expected = new Version(4, 7, 0);
|
||||
Assert.AreEqual(expected, result.DetermineInstalledVersion());
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public virtual void Initialize()
|
||||
{
|
||||
TestHelper.SetupLog4NetForTests();
|
||||
TestHelper.InitializeContentDirectories();
|
||||
|
||||
Path = TestHelper.CurrentAssemblyDirectory;
|
||||
AppDomain.CurrentDomain.SetData("DataDirectory", Path);
|
||||
|
||||
UmbracoSettings.UseLegacyXmlSchema = false;
|
||||
|
||||
Resolution.Freeze();
|
||||
|
||||
//Delete database file before continueing
|
||||
string filePath = string.Concat(Path, "\\UmbracoPetaPocoTests.sdf");
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
File.Delete(filePath);
|
||||
}
|
||||
|
||||
//Get the connectionstring settings from config
|
||||
var settings = ConfigurationManager.ConnectionStrings[Core.Configuration.GlobalSettings.UmbracoConnectionName];
|
||||
|
||||
//Create the Sql CE database
|
||||
var engine = new SqlCeEngine(settings.ConnectionString);
|
||||
engine.CreateDatabase();
|
||||
|
||||
SyntaxConfig.SqlSyntaxProvider = SqlCeSyntax.Provider;
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public virtual void TearDown()
|
||||
{
|
||||
SyntaxConfig.SqlSyntaxProvider = null;
|
||||
Resolution.IsFrozen = false;
|
||||
|
||||
TestHelper.CleanContentDirectories();
|
||||
|
||||
Path = TestHelper.CurrentAssemblyDirectory;
|
||||
AppDomain.CurrentDomain.SetData("DataDirectory", null);
|
||||
|
||||
//legacy API database connection close
|
||||
SqlCeContextGuardian.CloseBackgroundConnection();
|
||||
|
||||
string filePath = string.Concat(Path, "\\UmbracoPetaPocoTests.sdf");
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
File.Delete(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
public string Path { get; set; }
|
||||
|
||||
public UmbracoDatabase GetConfiguredDatabase()
|
||||
{
|
||||
return new UmbracoDatabase("Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf", "System.Data.SqlServerCe.4.0");
|
||||
}
|
||||
|
||||
public string GetDatabaseSpecificSqlScript()
|
||||
{
|
||||
return SqlScripts.SqlResources.SqlCeTotal_480;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Persistence.Migrations.Initial;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
|
||||
namespace Umbraco.Tests.Persistence
|
||||
{
|
||||
[TestFixture]
|
||||
public class SchemaValidationTest : BaseDatabaseFactoryTest
|
||||
{
|
||||
[SetUp]
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public override void TearDown()
|
||||
{
|
||||
base.TearDown();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DatabaseSchemaCreation_Produces_DatabaseSchemaResult_With_Zero_Errors()
|
||||
{
|
||||
// Arrange
|
||||
var db = DatabaseContext.Database;
|
||||
var schema = new DatabaseSchemaCreation(db);
|
||||
|
||||
// Act
|
||||
var result = schema.ValidateSchema();
|
||||
|
||||
// Assert
|
||||
Assert.That(result.Errors.Count, Is.EqualTo(0));
|
||||
Assert.AreEqual(result.DetermineInstalledVersion(), UmbracoVersion.Current);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,6 +175,7 @@
|
||||
<Compile Include="Migrations\Upgrades\SqlCeDataUpgradeTest.cs" />
|
||||
<Compile Include="Migrations\Upgrades\SqlCeUpgradeTest.cs" />
|
||||
<Compile Include="Migrations\Upgrades\SqlServerUpgradeTest.cs" />
|
||||
<Compile Include="Migrations\Upgrades\ValidateOlderSchemaTest.cs" />
|
||||
<Compile Include="Models\MediaXmlTest.cs" />
|
||||
<Compile Include="Persistence\Mappers\MappingResolverTests.cs" />
|
||||
<Compile Include="Persistence\Querying\ContentRepositorySqlClausesTest.cs" />
|
||||
@@ -183,6 +184,7 @@
|
||||
<Compile Include="Persistence\Querying\ExpressionTests.cs" />
|
||||
<Compile Include="Persistence\Querying\MediaRepositorySqlClausesTest.cs" />
|
||||
<Compile Include="Persistence\Querying\MediaTypeRepositorySqlClausesTest.cs" />
|
||||
<Compile Include="Persistence\SchemaValidationTest.cs" />
|
||||
<Compile Include="Persistence\SyntaxProvider\SqlSyntaxProviderTests.cs" />
|
||||
<Compile Include="PublishedContent\DynamicXmlTests.cs" />
|
||||
<Compile Include="PublishedContent\PublishedContentDataTableTests.cs" />
|
||||
@@ -311,7 +313,9 @@
|
||||
<Compile Include="Routing\UmbracoModuleTests.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="App.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
<None Include="TestHelpers\ExamineHelpers\umbraco.config" />
|
||||
<None Include="unit-test-log4net.config">
|
||||
|
||||
@@ -269,10 +269,42 @@
|
||||
<!-- installing umbraco -->
|
||||
<div class="tab install-tab" id="datebase-tab">
|
||||
<div class="container">
|
||||
<h1>Installing Umbraco</h1>
|
||||
<p>
|
||||
The Umbraco database is being configured. This process populates your chosen database with a blank Umbraco instance.
|
||||
</p>
|
||||
<asp:PlaceHolder ID="installProgress" runat="server" Visible="True">
|
||||
<div class="progress-status-container">
|
||||
<h1>Installing Umbraco</h1>
|
||||
<p>
|
||||
The Umbraco database is being configured. This process populates your chosen database with a blank Umbraco instance.
|
||||
</p>
|
||||
</div>
|
||||
<div class="result-status-container" style="display: none;">
|
||||
<h1>Database installed</h1>
|
||||
<div class="success">
|
||||
<p>
|
||||
Umbraco
|
||||
<%=UmbracoVersion.Current.ToString(3)%>
|
||||
has now been copied to your database. Press <b>Continue</b> to proceed.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</asp:PlaceHolder>
|
||||
<asp:PlaceHolder ID="upgradeProgress" runat="server" Visible="False">
|
||||
<div class="progress-status-container">
|
||||
<h1>Upgrading Umbraco</h1>
|
||||
<p>
|
||||
The Umbraco database is being configured. This process upgrades your Umbraco database.
|
||||
</p>
|
||||
</div>
|
||||
<div class="result-status-container" style="display: none;">
|
||||
<h1>Database upgraded</h1>
|
||||
<div class="success">
|
||||
<p>
|
||||
Your database has been upgraded to version:
|
||||
<%=UmbracoVersion.Current.ToString(3)%>.<br />
|
||||
Press <b>Continue</b> to proceed.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</asp:PlaceHolder>
|
||||
<div class="loader">
|
||||
<div class="hold">
|
||||
<div class="progress-bar">
|
||||
@@ -310,6 +342,8 @@
|
||||
if (json.Success) {
|
||||
$(".btn-box").show();
|
||||
$('.ui-progressbar-value').css("background-image", "url(../umbraco_client/installer/images/pbar.gif)");
|
||||
$(".result-status-container").show();
|
||||
$(".progress-status-container").hide();
|
||||
} else {
|
||||
$(".btn-continue").hide();
|
||||
$(".btn-back").show();
|
||||
@@ -320,32 +354,4 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
</asp:PlaceHolder>
|
||||
|
||||
<asp:Panel ID="confirms" runat="server" Visible="False">
|
||||
<asp:PlaceHolder ID="installConfirm" runat="server" Visible="False">
|
||||
<h1>Database installed</h1>
|
||||
<div class="success">
|
||||
<p>
|
||||
Umbraco
|
||||
<%=UmbracoVersion.Current.ToString(3)%>
|
||||
has now been copied to your database. Press <b>Continue</b> to proceed.
|
||||
</p>
|
||||
</div>
|
||||
</asp:PlaceHolder>
|
||||
<asp:PlaceHolder ID="upgradeConfirm" runat="server" Visible="False">
|
||||
<h1>Database upgraded</h1>
|
||||
<div class="success">
|
||||
<p>
|
||||
Your database has been upgraded to version:
|
||||
<%=UmbracoVersion.Current.ToString(3)%>.<br />
|
||||
Press <b>Continue</b> to proceed.
|
||||
</p>
|
||||
</div>
|
||||
</asp:PlaceHolder>
|
||||
<!-- btn box -->
|
||||
<footer class="btn-box" style="display: none;">
|
||||
<div class="t"> </div>
|
||||
<asp:LinkButton class="btn-step btn btn-continue" runat="server" OnClick="gotoNextStep"><span>Continue</span></asp:LinkButton>
|
||||
</footer>
|
||||
</asp:Panel>
|
||||
</asp:PlaceHolder>
|
||||
@@ -66,7 +66,7 @@
|
||||
<DbProviderFactories>
|
||||
<remove invariant="System.Data.SqlServerCe.4.0"/>
|
||||
<add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91" />
|
||||
<remove invariant="MySql.Data.MySqlClient"/>
|
||||
<remove invariant="MySql.Data.MySqlClient"/>
|
||||
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.6.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
|
||||
</DbProviderFactories>
|
||||
</system.data>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using umbraco.cms.businesslogic.installer;
|
||||
using umbraco.IO;
|
||||
@@ -35,8 +36,16 @@ namespace umbraco.presentation.install.steps.Definitions
|
||||
public override bool Completed()
|
||||
{
|
||||
// Fresh installs don't have a version number so this step cannot be complete yet
|
||||
if (string.IsNullOrEmpty(Umbraco.Core.Configuration.GlobalSettings.ConfigurationStatus))
|
||||
return false;
|
||||
if (string.IsNullOrEmpty(Umbraco.Core.Configuration.GlobalSettings.ConfigurationStatus))
|
||||
{
|
||||
//Even though the ConfigurationStatus is blank we try to determine the version if we can connect to the database
|
||||
var result = ApplicationContext.Current.DatabaseContext.ValidateDatabaseSchema();
|
||||
var determinedVersion = result.DetermineInstalledVersion();
|
||||
if (determinedVersion.Equals(new Version(0, 0, 0)))
|
||||
return false;
|
||||
|
||||
return UmbracoVersion.Current < determinedVersion;
|
||||
}
|
||||
|
||||
var configuredVersion = new Version(Umbraco.Core.Configuration.GlobalSettings.ConfigurationStatus);
|
||||
var targetVersion = UmbracoVersion.Current;
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using umbraco.cms.businesslogic.installer;
|
||||
using umbraco.cms.businesslogic.installer;
|
||||
|
||||
namespace umbraco.presentation.install.steps.Definitions
|
||||
{
|
||||
|
||||
@@ -269,10 +269,42 @@
|
||||
<!-- installing umbraco -->
|
||||
<div class="tab install-tab" id="datebase-tab">
|
||||
<div class="container">
|
||||
<h1>Installing Umbraco</h1>
|
||||
<p>
|
||||
The Umbraco database is being configured. This process populates your chosen database with a blank Umbraco instance.
|
||||
</p>
|
||||
<asp:PlaceHolder ID="installProgress" runat="server" Visible="True">
|
||||
<div class="progress-status-container">
|
||||
<h1>Installing Umbraco</h1>
|
||||
<p>
|
||||
The Umbraco database is being configured. This process populates your chosen database with a blank Umbraco instance.
|
||||
</p>
|
||||
</div>
|
||||
<div class="result-status-container" style="display: none;">
|
||||
<h1>Database installed</h1>
|
||||
<div class="success">
|
||||
<p>
|
||||
Umbraco
|
||||
<%=UmbracoVersion.Current.ToString(3)%>
|
||||
has now been copied to your database. Press <b>Continue</b> to proceed.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</asp:PlaceHolder>
|
||||
<asp:PlaceHolder ID="upgradeProgress" runat="server" Visible="False">
|
||||
<div class="progress-status-container">
|
||||
<h1>Upgrading Umbraco</h1>
|
||||
<p>
|
||||
The Umbraco database is being configured. This process upgrades your Umbraco database.
|
||||
</p>
|
||||
</div>
|
||||
<div class="result-status-container" style="display: none;">
|
||||
<h1>Database upgraded</h1>
|
||||
<div class="success">
|
||||
<p>
|
||||
Your database has been upgraded to version:
|
||||
<%=UmbracoVersion.Current.ToString(3)%>.<br />
|
||||
Press <b>Continue</b> to proceed.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</asp:PlaceHolder>
|
||||
<div class="loader">
|
||||
<div class="hold">
|
||||
<div class="progress-bar">
|
||||
@@ -310,6 +342,8 @@
|
||||
if (json.Success) {
|
||||
$(".btn-box").show();
|
||||
$('.ui-progressbar-value').css("background-image", "url(../umbraco_client/installer/images/pbar.gif)");
|
||||
$(".result-status-container").show();
|
||||
$(".progress-status-container").hide();
|
||||
} else {
|
||||
$(".btn-continue").hide();
|
||||
$(".btn-back").show();
|
||||
@@ -320,32 +354,4 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
</asp:PlaceHolder>
|
||||
|
||||
<asp:Panel ID="confirms" runat="server" Visible="False">
|
||||
<asp:PlaceHolder ID="installConfirm" runat="server" Visible="False">
|
||||
<h1>Database installed</h1>
|
||||
<div class="success">
|
||||
<p>
|
||||
Umbraco
|
||||
<%=UmbracoVersion.Current.ToString(3)%>
|
||||
has now been copied to your database. Press <b>Continue</b> to proceed.
|
||||
</p>
|
||||
</div>
|
||||
</asp:PlaceHolder>
|
||||
<asp:PlaceHolder ID="upgradeConfirm" runat="server" Visible="False">
|
||||
<h1>Database upgraded</h1>
|
||||
<div class="success">
|
||||
<p>
|
||||
Your database has been upgraded to version:
|
||||
<%=UmbracoVersion.Current.ToString(3)%>.<br />
|
||||
Press <b>Continue</b> to proceed.
|
||||
</p>
|
||||
</div>
|
||||
</asp:PlaceHolder>
|
||||
<!-- btn box -->
|
||||
<footer class="btn-box" style="display: none;">
|
||||
<div class="t"> </div>
|
||||
<asp:LinkButton class="btn-step btn btn-continue" runat="server" OnClick="gotoNextStep"><span>Continue</span></asp:LinkButton>
|
||||
</footer>
|
||||
</asp:Panel>
|
||||
</asp:PlaceHolder>
|
||||
@@ -71,8 +71,29 @@ namespace umbraco.presentation.install.steps
|
||||
{
|
||||
// Does the user have to enter a connection string?
|
||||
if (settings.Visible && !Page.IsPostBack)
|
||||
ShowDatabaseSettings();
|
||||
{
|
||||
//If the connection string is already present in web.config we don't need to show the settings page and we jump to installing/upgrading.
|
||||
if (
|
||||
ConfigurationManager.ConnectionStrings[
|
||||
Umbraco.Core.Configuration.GlobalSettings.UmbracoConnectionName] == null
|
||||
||
|
||||
string.IsNullOrEmpty(
|
||||
ConfigurationManager.ConnectionStrings[
|
||||
Umbraco.Core.Configuration.GlobalSettings.UmbracoConnectionName].ConnectionString))
|
||||
{
|
||||
installProgress.Visible = true;
|
||||
upgradeProgress.Visible = false;
|
||||
ShowDatabaseSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
installProgress.Visible = false;
|
||||
upgradeProgress.Visible = true;
|
||||
|
||||
settings.Visible = false;
|
||||
installing.Visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
+4
-13
@@ -220,30 +220,21 @@ namespace umbraco.presentation.install.steps {
|
||||
protected global::System.Web.UI.WebControls.PlaceHolder installing;
|
||||
|
||||
/// <summary>
|
||||
/// confirms control.
|
||||
/// installProgress control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.Panel confirms;
|
||||
protected global::System.Web.UI.WebControls.PlaceHolder installProgress;
|
||||
|
||||
/// <summary>
|
||||
/// installConfirm control.
|
||||
/// upgradeProgress control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.PlaceHolder installConfirm;
|
||||
|
||||
/// <summary>
|
||||
/// upgradeConfirm control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.PlaceHolder upgradeConfirm;
|
||||
protected global::System.Web.UI.WebControls.PlaceHolder upgradeProgress;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
using umbraco;
|
||||
using System;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace umbraco.presentation.install
|
||||
{
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Web;
|
||||
using System.Web.UI.WebControls;
|
||||
using System.Web.UI.HtmlControls;
|
||||
|
||||
/// <summary>
|
||||
/// Summary description for welcome.
|
||||
/// </summary>
|
||||
@@ -17,24 +11,24 @@ namespace umbraco.presentation.install
|
||||
|
||||
protected void Page_Load(object sender, System.EventArgs e)
|
||||
{
|
||||
var result = ApplicationContext.Current.DatabaseContext.ValidateDatabaseSchema();
|
||||
var determinedVersion = result.DetermineInstalledVersion();
|
||||
|
||||
// Display the Umbraco upgrade message if Umbraco is already installed
|
||||
if (String.IsNullOrWhiteSpace(GlobalSettings.ConfigurationStatus) == false)
|
||||
if (String.IsNullOrWhiteSpace(GlobalSettings.ConfigurationStatus) == false || determinedVersion.Equals(new Version(0, 0, 0)) == false)
|
||||
{
|
||||
ph_install.Visible = false;
|
||||
ph_upgrade.Visible = true;
|
||||
}
|
||||
|
||||
// Check for config!
|
||||
if (GlobalSettings.Configured)
|
||||
{
|
||||
Application.Lock();
|
||||
Application["umbracoNeedConfiguration"] = null;
|
||||
Application.UnLock();
|
||||
Response.Redirect(Request.QueryString["url"] ?? "/", true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Check for config!
|
||||
if (GlobalSettings.Configured)
|
||||
{
|
||||
Application.Lock();
|
||||
Application["umbracoNeedConfiguration"] = null;
|
||||
Application.UnLock();
|
||||
Response.Redirect(Request.QueryString["url"] ?? "/", true);
|
||||
}
|
||||
}
|
||||
|
||||
protected void gotoNextStep(object sender, EventArgs e) {
|
||||
|
||||
@@ -48,6 +48,7 @@ namespace umbraco.cms.businesslogic
|
||||
private bool _hasChildrenInitialized;
|
||||
private string m_image = "default.png";
|
||||
private bool? _isTrashed = null;
|
||||
private IUmbracoEntity _entity;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -55,6 +56,7 @@ namespace umbraco.cms.businesslogic
|
||||
|
||||
private static readonly string m_DefaultIconCssFile = IOHelper.MapPath(SystemDirectories.Umbraco_client + "/Tree/treeIcons.css");
|
||||
private static List<string> m_DefaultIconClasses = new List<string>();
|
||||
|
||||
private static void initializeIconClasses()
|
||||
{
|
||||
StreamReader re = File.OpenText(m_DefaultIconCssFile);
|
||||
@@ -394,9 +396,10 @@ namespace umbraco.cms.businesslogic
|
||||
PopulateCMSNodeFromReader(reader);
|
||||
}
|
||||
|
||||
protected internal CMSNode(IEntity entity)
|
||||
protected internal CMSNode(IUmbracoEntity entity)
|
||||
{
|
||||
_id = entity.Id;
|
||||
_entity = entity;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -576,6 +579,7 @@ order by level,sortOrder";
|
||||
/// Moves the CMSNode from the current position in the hierarchy to the target
|
||||
/// </summary>
|
||||
/// <param name="NewParentId">Target CMSNode id</param>
|
||||
[Obsolete("Obsolete, Use Umbraco.Core.Services.ContentService.Move() or Umbraco.Core.Services.MediaService.Move()", false)]
|
||||
public virtual void Move(int newParentId)
|
||||
{
|
||||
CMSNode parent = new CMSNode(newParentId);
|
||||
@@ -705,6 +709,9 @@ order by level,sortOrder";
|
||||
{
|
||||
_sortOrder = value;
|
||||
SqlHelper.ExecuteNonQuery("update umbracoNode set sortOrder = '" + value + "' where id = " + this.Id.ToString());
|
||||
|
||||
if (_entity != null)
|
||||
_entity.SortOrder = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -766,6 +773,9 @@ order by level,sortOrder";
|
||||
{
|
||||
_parentid = value.Id;
|
||||
SqlHelper.ExecuteNonQuery("update umbracoNode set parentId = " + value.Id.ToString() + " where id = " + this.Id.ToString());
|
||||
|
||||
if (_entity != null)
|
||||
_entity.ParentId = value.Id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -781,6 +791,9 @@ order by level,sortOrder";
|
||||
{
|
||||
_path = value;
|
||||
SqlHelper.ExecuteNonQuery("update umbracoNode set path = '" + _path + "' where id = " + this.Id.ToString());
|
||||
|
||||
if (_entity != null)
|
||||
_entity.Path = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -796,6 +809,9 @@ order by level,sortOrder";
|
||||
{
|
||||
_level = value;
|
||||
SqlHelper.ExecuteNonQuery("update umbracoNode set level = " + _level.ToString() + " where id = " + this.Id.ToString());
|
||||
|
||||
if (_entity != null)
|
||||
_entity.Level = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -915,6 +931,8 @@ order by level,sortOrder";
|
||||
SqlHelper.CreateParameter("@text", value.Trim()),
|
||||
SqlHelper.CreateParameter("@id", this.Id));
|
||||
|
||||
if (_entity != null)
|
||||
_entity.Name = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -966,6 +984,9 @@ order by level,sortOrder";
|
||||
protected void SetText(string txt)
|
||||
{
|
||||
_text = txt;
|
||||
|
||||
if (_entity != null)
|
||||
_entity.Name = txt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1086,6 +1107,7 @@ order by level,sortOrder";
|
||||
_userId = content.CreatorId;
|
||||
_createDate = content.CreateDate;
|
||||
_isTrashed = content.Trashed;
|
||||
_entity = content;
|
||||
}
|
||||
|
||||
internal protected void PopulateCMSNodeFromContentTypeBase(IContentTypeBase contentType, Guid objectType)
|
||||
@@ -1100,6 +1122,7 @@ order by level,sortOrder";
|
||||
_userId = contentType.CreatorId;
|
||||
_createDate = contentType.CreateDate;
|
||||
_isTrashed = false;
|
||||
_entity = contentType;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
Reference in New Issue
Block a user