Files
Umbraco-CMS/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaResult.cs
T

188 lines
8.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Semver;
using Umbraco.Core.Configuration;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Services;
namespace Umbraco.Core.Persistence.Migrations.Initial
{
public class DatabaseSchemaResult
{
public DatabaseSchemaResult()
{
Errors = new List<Tuple<string, string>>();
TableDefinitions = new List<TableDefinition>();
ValidTables = new List<string>();
ValidColumns = new List<string>();
ValidConstraints = new List<string>();
ValidIndexes = new List<string>();
}
public List<Tuple<string, string>> Errors { 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; }
public List<string> ValidIndexes { get; set; }
internal IEnumerable<DbIndexDefinition> DbIndexDefinitions { get; set; }
/// <summary>
/// Checks in the db which version is installed based on the migrations that have been run
/// </summary>
/// <param name="migrationEntryService"></param>
/// <returns></returns>
public SemVersion DetermineInstalledVersionByMigrations(IMigrationEntryService migrationEntryService)
{
var allMigrations = migrationEntryService.GetAll(GlobalSettings.UmbracoMigrationName);
var mostrecent = allMigrations.OrderByDescending(x => x.Version).Select(x => x.Version).FirstOrDefault();
return mostrecent ?? new SemVersion(new Version(0, 0, 0));
}
/// <summary>
/// Determines the version of the currently installed database by detecting the current database structure
/// </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 or if TableDefinitions tables + columns correspond to valid tables + columns then we're at current version
if (Errors.Any() == false ||
(TableDefinitions.All(x => ValidTables.Contains(x.Name))
&& TableDefinitions.SelectMany(definition => definition.Columns).All(x => ValidColumns.Contains(x.Name))))
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.InvariantEquals("umbracoApp") || x.Item2.InvariantEquals("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.InvariantContains("umbracoUser2app_umbracoApp")
|| x.Item2.InvariantContains("umbracoAppTree_umbracoApp"))))
{
return new Version(4, 7, 0);
}
return new Version(4, 8, 0);
}
//if the error is for umbracoServer
if (Errors.Any(x => x.Item1.Equals("Table") && (x.Item2.InvariantEquals("umbracoServer"))))
{
return new Version(6, 0, 0);
}
//if the error indicates a problem with the column cmsMacroProperty.macroPropertyType then it is not version 7
// since these columns get removed in v7
if (Errors.Any(x => x.Item1.Equals("Column") && (x.Item2.InvariantEquals("cmsMacroProperty,macroPropertyType"))))
{
//if the error is for this IX_umbracoNodeTrashed which is added in 6.2 AND in 7.1 but we do not have the above columns
// then it must mean that we aren't on 6.2 so must be 6.1
if (Errors.Any(x => x.Item1.Equals("Index") && (x.Item2.InvariantEquals("IX_umbracoNodeTrashed"))))
{
return new Version(6, 1, 0);
}
else
{
//if there are no errors for that index, then the person must have 6.2 installed
return new Version(6, 2, 0);
}
}
//if the error indicates a problem with the constraint FK_cmsContent_cmsContentType_nodeId then it is not version 7.2
// since this gets added in 7.2.0 so it must be the previous version
if (Errors.Any(x => x.Item1.Equals("Constraint") && (x.Item2.InvariantEquals("FK_cmsContent_cmsContentType_nodeId"))))
{
return new Version(7, 0, 0);
}
//if the error is for umbracoAccess it must be the previous version to 7.3 since that is when it is added
if (Errors.Any(x => x.Item1.Equals("Table") && (x.Item2.InvariantEquals("umbracoAccess"))))
{
return new Version(7, 2, 5);
}
//if the error is for umbracoDeployChecksum it must be the previous version to 7.4 since that is when it is added
if (Errors.Any(x => x.Item1.Equals("Table") && (x.Item2.InvariantEquals("umbracoDeployChecksum"))))
{
return new Version(7, 3, 4);
}
return UmbracoVersion.Current;
}
/// <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(" ");
}
//Index error summary
if (Errors.Any(x => x.Item1.Equals("Index")))
{
sb.AppendLine("The following indexes were found in the database, but are not in the current schema:");
sb.AppendLine(string.Join(",", Errors.Where(x => x.Item1.Equals("Index")).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 (SqlSyntaxContext.SqlSyntaxProvider is MySqlSyntaxProvider)
{
sb.AppendLine("Please note that the constraints could not be validated because the current dataprovider is MySql.");
}
return sb.ToString();
}
}
}