diff --git a/build/NuSpecs/UmbracoCms.Core.nuspec b/build/NuSpecs/UmbracoCms.Core.nuspec
index 4fe812dbeb..0c7d51334e 100644
--- a/build/NuSpecs/UmbracoCms.Core.nuspec
+++ b/build/NuSpecs/UmbracoCms.Core.nuspec
@@ -32,9 +32,9 @@
-
-
-
+
+
+
diff --git a/build/NuSpecs/tools/Web.config.install.xdt b/build/NuSpecs/tools/Web.config.install.xdt
index fbe2cbe439..f7fbad09bd 100644
--- a/build/NuSpecs/tools/Web.config.install.xdt
+++ b/build/NuSpecs/tools/Web.config.install.xdt
@@ -22,10 +22,7 @@
-
-
-
-
+
@@ -51,6 +48,8 @@
+
+
>
diff --git a/build/UmbracoVersion.txt b/build/UmbracoVersion.txt
index b31e79056f..7cb235f023 100644
--- a/build/UmbracoVersion.txt
+++ b/build/UmbracoVersion.txt
@@ -1,3 +1,3 @@
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
7.3.0
-beta3
\ No newline at end of file
+RC
\ No newline at end of file
diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs
index dbc0f2d41d..ae85cd82ea 100644
--- a/src/SolutionInfo.cs
+++ b/src/SolutionInfo.cs
@@ -12,4 +12,4 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.3.0")]
-[assembly: AssemblyInformationalVersion("7.3.0-beta3")]
\ No newline at end of file
+[assembly: AssemblyInformationalVersion("7.3.0-RC")]
\ No newline at end of file
diff --git a/src/Umbraco.Core/ApplicationContext.cs b/src/Umbraco.Core/ApplicationContext.cs
index 7e306a6361..4aef011d05 100644
--- a/src/Umbraco.Core/ApplicationContext.cs
+++ b/src/Umbraco.Core/ApplicationContext.cs
@@ -2,6 +2,7 @@
using System.Configuration;
using System.Threading;
using System.Threading.Tasks;
+using System.Web;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.ObjectResolution;
@@ -259,22 +260,13 @@ namespace Umbraco.Core
{
get
{
- // if initialized, return
- if (_umbracoApplicationUrl != null) return _umbracoApplicationUrl;
-
- // try settings
- ServerEnvironmentHelper.TrySetApplicationUrlFromSettings(this, ProfilingLogger.Logger, UmbracoConfig.For.UmbracoSettings());
-
- // and return what we have, may be null
+ ApplicationUrlHelper.EnsureApplicationUrl(this);
return _umbracoApplicationUrl;
}
- set
- {
- _umbracoApplicationUrl = value;
- }
}
- internal string _umbracoApplicationUrl; // internal for tests
+ // ReSharper disable once InconsistentNaming
+ internal string _umbracoApplicationUrl;
private Lazy _configured;
internal MainDom MainDom { get; private set; }
@@ -379,6 +371,11 @@ namespace Umbraco.Core
internal set { _services = value; }
}
+ internal ServerRole GetCurrentServerRole()
+ {
+ var registrar = ServerRegistrarResolver.Current.Registrar as IServerRegistrar2;
+ return registrar == null ? ServerRole.Unknown : registrar.GetCurrentServerRole();
+ }
private volatile bool _disposed;
private readonly ReaderWriterLockSlim _disposalLocker = new ReaderWriterLockSlim();
diff --git a/src/Umbraco.Core/Configuration/UmbracoVersion.cs b/src/Umbraco.Core/Configuration/UmbracoVersion.cs
index ed5265446f..30f59875e8 100644
--- a/src/Umbraco.Core/Configuration/UmbracoVersion.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoVersion.cs
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Configuration
/// Gets the version comment (like beta or RC).
///
/// The version comment.
- public static string CurrentComment { get { return "beta3"; } }
+ public static string CurrentComment { get { return "RC"; } }
// Get the version of the umbraco.dll by looking at a class in that dll
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
diff --git a/src/Umbraco.Core/Constants-ObjectTypes.cs b/src/Umbraco.Core/Constants-ObjectTypes.cs
index 4f225aaccb..f737a68f02 100644
--- a/src/Umbraco.Core/Constants-ObjectTypes.cs
+++ b/src/Umbraco.Core/Constants-ObjectTypes.cs
@@ -2,13 +2,13 @@
namespace Umbraco.Core
{
- public static partial class Constants
- {
- ///
- /// Defines the identifiers for Umbraco object types as constants for easy centralized access/management.
- ///
- public static class ObjectTypes
- {
+ public static partial class Constants
+ {
+ ///
+ /// Defines the identifiers for Umbraco object types as constants for easy centralized access/management.
+ ///
+ public static class ObjectTypes
+ {
///
/// Guid for a doc type container
///
@@ -19,84 +19,89 @@ namespace Umbraco.Core
///
public const string MediaTypeContainer = "42AEF799-B288-4744-9B10-BE144B73CDC4";
- ///
- /// Guid for a Content Item object.
- ///
- public const string ContentItem = "10E2B09F-C28B-476D-B77A-AA686435E44A";
+ ///
+ /// Guid for a Content Item object.
+ ///
+ public const string ContentItem = "10E2B09F-C28B-476D-B77A-AA686435E44A";
- ///
- /// Guid for a Content Item Type object.
- ///
- public const string ContentItemType = "7A333C54-6F43-40A4-86A2-18688DC7E532";
+ ///
+ /// Guid for a Content Item Type object.
+ ///
+ public const string ContentItemType = "7A333C54-6F43-40A4-86A2-18688DC7E532";
- ///
- /// Guid for the Content Recycle Bin.
- ///
- public const string ContentRecycleBin = "01BB7FF2-24DC-4C0C-95A2-C24EF72BBAC8";
+ ///
+ /// Guid for the Content Recycle Bin.
+ ///
+ public const string ContentRecycleBin = "01BB7FF2-24DC-4C0C-95A2-C24EF72BBAC8";
- ///
- /// Guid for a DataType object.
- ///
- public const string DataType = "30A2A501-1978-4DDB-A57B-F7EFED43BA3C";
+ ///
+ /// Guid for a DataType object.
+ ///
+ public const string DataType = "30A2A501-1978-4DDB-A57B-F7EFED43BA3C";
- ///
- /// Guid for a Document object.
- ///
- public const string Document = "C66BA18E-EAF3-4CFF-8A22-41B16D66A972";
+ ///
+ /// Guid for a Document object.
+ ///
+ public const string Document = "C66BA18E-EAF3-4CFF-8A22-41B16D66A972";
- ///
- /// Guid for a Document Type object.
- ///
- public const string DocumentType = "A2CB7800-F571-4787-9638-BC48539A0EFB";
+ ///
+ /// Guid for a Document Type object.
+ ///
+ public const string DocumentType = "A2CB7800-F571-4787-9638-BC48539A0EFB";
- ///
- /// Guid for a Media object.
- ///
- public const string Media = "B796F64C-1F99-4FFB-B886-4BF4BC011A9C";
+ ///
+ /// Guid for a Media object.
+ ///
+ public const string Media = "B796F64C-1F99-4FFB-B886-4BF4BC011A9C";
- ///
- /// Guid for the Media Recycle Bin.
- ///
- public const string MediaRecycleBin = "CF3D8E34-1C1C-41e9-AE56-878B57B32113";
+ ///
+ /// Guid for the Media Recycle Bin.
+ ///
+ public const string MediaRecycleBin = "CF3D8E34-1C1C-41e9-AE56-878B57B32113";
- ///
- /// Guid for a Media Type object.
- ///
- public const string MediaType = "4EA4382B-2F5A-4C2B-9587-AE9B3CF3602E";
+ ///
+ /// Guid for a Media Type object.
+ ///
+ public const string MediaType = "4EA4382B-2F5A-4C2B-9587-AE9B3CF3602E";
- ///
- /// Guid for a Member object.
- ///
- public const string Member = "39EB0F98-B348-42A1-8662-E7EB18487560";
+ ///
+ /// Guid for a Member object.
+ ///
+ public const string Member = "39EB0F98-B348-42A1-8662-E7EB18487560";
- ///
- /// Guid for a Member Group object.
- ///
- public const string MemberGroup = "366E63B9-880F-4E13-A61C-98069B029728";
+ ///
+ /// Guid for a Member Group object.
+ ///
+ public const string MemberGroup = "366E63B9-880F-4E13-A61C-98069B029728";
- ///
- /// Guid for a Member Type object.
- ///
- public const string MemberType = "9B5416FB-E72F-45A9-A07B-5A9A2709CE43";
+ ///
+ /// Guid for a Member Type object.
+ ///
+ public const string MemberType = "9B5416FB-E72F-45A9-A07B-5A9A2709CE43";
- ///
- /// Guid for a Stylesheet object.
- ///
+ ///
+ /// Guid for a Stylesheet object.
+ ///
[Obsolete("This no longer exists in the database")]
public const string Stylesheet = "9F68DA4F-A3A8-44C2-8226-DCBD125E4840";
[Obsolete("This no longer exists in the database")]
internal const string StylesheetProperty = "5555da4f-a123-42b2-4488-dcdfb25e4111";
- ///
- /// Guid for the System Root.
- ///
- public const string SystemRoot = "EA7D8624-4CFE-4578-A871-24AA946BF34D";
+ ///
+ /// Guid for the System Root.
+ ///
+ public const string SystemRoot = "EA7D8624-4CFE-4578-A871-24AA946BF34D";
- ///
- /// Guid for a Template object.
- ///
- public const string Template = "6FBDE604-4178-42CE-A10B-8A2600A2F07D";
- }
- }
+ ///
+ /// Guid for a Template object.
+ ///
+ public const string Template = "6FBDE604-4178-42CE-A10B-8A2600A2F07D";
+
+ ///
+ /// Guid for a Lock object.
+ ///
+ public const string LockObject = "87A9F1FF-B1E4-4A25-BABB-465A4A47EC41";
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Constants-System.cs b/src/Umbraco.Core/Constants-System.cs
index b72afa265f..82e3a1ff3f 100644
--- a/src/Umbraco.Core/Constants-System.cs
+++ b/src/Umbraco.Core/Constants-System.cs
@@ -26,6 +26,8 @@
public const int DefaultMediaListViewDataTypeId = -96;
public const int DefaultMembersListViewDataTypeId = -97;
+ // identifiers for lock objects
+ public const int ServersLock = -331;
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/DelegateExtensions.cs b/src/Umbraco.Core/DelegateExtensions.cs
new file mode 100644
index 0000000000..78450448e2
--- /dev/null
+++ b/src/Umbraco.Core/DelegateExtensions.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Diagnostics;
+using System.Threading;
+
+namespace Umbraco.Core
+{
+ public static class DelegateExtensions
+ {
+ public static Attempt RetryUntilSuccessOrTimeout(this Func> task, TimeSpan timeout, TimeSpan pause)
+ {
+ if (pause.TotalMilliseconds < 0)
+ {
+ throw new ArgumentException("pause must be >= 0 milliseconds");
+ }
+ var stopwatch = Stopwatch.StartNew();
+ do
+ {
+ var result = task();
+ if (result) { return result; }
+ Thread.Sleep((int)pause.TotalMilliseconds);
+ }
+ while (stopwatch.Elapsed < timeout);
+ return Attempt.Fail();
+ }
+
+ public static Attempt RetryUntilSuccessOrMaxAttempts(this Func> task, int totalAttempts, TimeSpan pause)
+ {
+ if (pause.TotalMilliseconds < 0)
+ {
+ throw new ArgumentException("pause must be >= 0 milliseconds");
+ }
+ int attempts = 0;
+ do
+ {
+ attempts++;
+ var result = task(attempts);
+ if (result) { return result; }
+ Thread.Sleep((int)pause.TotalMilliseconds);
+ }
+ while (attempts < totalAttempts);
+ return Attempt.Fail();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/IO/IOHelper.cs b/src/Umbraco.Core/IO/IOHelper.cs
index 2d87f634f4..286acf0285 100644
--- a/src/Umbraco.Core/IO/IOHelper.cs
+++ b/src/Umbraco.Core/IO/IOHelper.cs
@@ -152,12 +152,7 @@ namespace Umbraco.Core.IO
/// A value indicating whether the filepath is valid.
internal static bool VerifyEditPath(string filePath, string validDir)
{
- if (filePath.StartsWith(MapPath(SystemDirectories.Root)) == false)
- filePath = MapPath(filePath);
- if (validDir.StartsWith(MapPath(SystemDirectories.Root)) == false)
- validDir = MapPath(validDir);
-
- return filePath.StartsWith(validDir);
+ return VerifyEditPath(filePath, new[] { validDir });
}
///
@@ -182,15 +177,31 @@ namespace Umbraco.Core.IO
/// A value indicating whether the filepath is valid.
internal static bool VerifyEditPath(string filePath, IEnumerable validDirs)
{
+ // this is called from ScriptRepository, PartialViewRepository, etc.
+ // filePath is the fullPath (rooted, filesystem path, can be trusted)
+ // validDirs are virtual paths (eg ~/Views)
+ //
+ // except that for templates, filePath actually is a virtual path
+
+ //TODO
+ // what's below is dirty, there are too many ways to get the root dir, etc.
+ // not going to fix everything today
+
+ var mappedRoot = MapPath(SystemDirectories.Root);
+ if (filePath.StartsWith(mappedRoot) == false)
+ filePath = MapPath(filePath);
+
+ // yes we can (see above)
+ //// don't trust what we get, it may contain relative segments
+ //filePath = Path.GetFullPath(filePath);
+
foreach (var dir in validDirs)
{
var validDir = dir;
- if (filePath.StartsWith(MapPath(SystemDirectories.Root)) == false)
- filePath = MapPath(filePath);
- if (validDir.StartsWith(MapPath(SystemDirectories.Root)) == false)
+ if (validDir.StartsWith(mappedRoot) == false)
validDir = MapPath(validDir);
- if (filePath.StartsWith(validDir))
+ if (PathStartsWith(filePath, validDir, Path.DirectorySeparatorChar))
return true;
}
@@ -219,11 +230,8 @@ namespace Umbraco.Core.IO
/// A value indicating whether the filepath is valid.
internal static bool VerifyFileExtension(string filePath, List validFileExtensions)
{
- if (filePath.StartsWith(MapPath(SystemDirectories.Root)) == false)
- filePath = MapPath(filePath);
- var f = new FileInfo(filePath);
-
- return validFileExtensions.Contains(f.Extension.Substring(1));
+ var ext = Path.GetExtension(filePath);
+ return ext != null && validFileExtensions.Contains(ext.TrimStart('.'));
}
///
@@ -240,6 +248,16 @@ namespace Umbraco.Core.IO
return true;
}
+ public static bool PathStartsWith(string path, string root, char separator)
+ {
+ // either it is identical to root,
+ // or it is root + separator + anything
+
+ if (path.StartsWith(root, StringComparison.OrdinalIgnoreCase) == false) return false;
+ if (path.Length == root.Length) return true;
+ if (path.Length < root.Length) return false;
+ return path[root.Length] == separator;
+ }
///
/// Returns the path to the root of the application, by getting the path to where the assembly where this
diff --git a/src/Umbraco.Core/IO/PhysicalFileSystem.cs b/src/Umbraco.Core/IO/PhysicalFileSystem.cs
index 13df315960..47daff932d 100644
--- a/src/Umbraco.Core/IO/PhysicalFileSystem.cs
+++ b/src/Umbraco.Core/IO/PhysicalFileSystem.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
+using System.IO;
using System.Linq;
using Umbraco.Core.Logging;
@@ -9,7 +8,12 @@ namespace Umbraco.Core.IO
{
public class PhysicalFileSystem : IFileSystem
{
- internal string RootPath { get; private set; }
+ // the rooted, filesystem path, using directory separator chars, NOT ending with a separator
+ // eg "c:" or "c:\path\to\site" or "\\server\path"
+ private readonly string _rootPath;
+
+ // the ??? url, using url separator chars, NOT ending with a separator
+ // eg "" (?) or "/Scripts" or ???
private readonly string _rootUrl;
public PhysicalFileSystem(string virtualRoot)
@@ -18,8 +22,13 @@ namespace Umbraco.Core.IO
if (virtualRoot.StartsWith("~/") == false)
throw new ArgumentException("The virtualRoot argument must be a virtual path and start with '~/'");
- RootPath = IOHelper.MapPath(virtualRoot);
+ _rootPath = IOHelper.MapPath(virtualRoot);
+ _rootPath = EnsureDirectorySeparatorChar(_rootPath);
+ _rootPath = _rootPath.TrimEnd(Path.DirectorySeparatorChar);
+
_rootUrl = IOHelper.ResolveUrl(virtualRoot);
+ _rootUrl = EnsureUrlSeparatorChar(_rootUrl);
+ _rootUrl = _rootUrl.TrimEnd('/');
}
public PhysicalFileSystem(string rootPath, string rootUrl)
@@ -33,18 +42,31 @@ namespace Umbraco.Core.IO
if (rootPath.StartsWith("~/"))
throw new ArgumentException("The rootPath argument cannot be a virtual path and cannot start with '~/'");
- RootPath = rootPath;
- _rootUrl = rootUrl;
+ // rootPath should be... rooted, as in, it's a root path!
+ // but the test suite App.config cannot really "root" anything so we'll have to do it here
+
+ //var localRoot = AppDomain.CurrentDomain.BaseDirectory;
+ var localRoot = IOHelper.GetRootDirectorySafe();
+ if (Path.IsPathRooted(rootPath) == false)
+ {
+ rootPath = Path.Combine(localRoot, rootPath);
+ }
+
+ rootPath = EnsureDirectorySeparatorChar(rootPath);
+ rootUrl = EnsureUrlSeparatorChar(rootUrl);
+
+ _rootPath = rootPath.TrimEnd(Path.DirectorySeparatorChar);
+ _rootUrl = rootUrl.TrimEnd('/');
}
public IEnumerable GetDirectories(string path)
{
- path = EnsureTrailingSeparator(GetFullPath(path));
+ var fullPath = GetFullPath(path);
try
{
- if (Directory.Exists(path))
- return Directory.EnumerateDirectories(path).Select(GetRelativePath);
+ if (Directory.Exists(fullPath))
+ return Directory.EnumerateDirectories(fullPath).Select(GetRelativePath);
}
catch (UnauthorizedAccessException ex)
{
@@ -65,12 +87,13 @@ namespace Umbraco.Core.IO
public void DeleteDirectory(string path, bool recursive)
{
- if (DirectoryExists(path) == false)
+ var fullPath = GetFullPath(path);
+ if (Directory.Exists(fullPath) == false)
return;
try
{
- Directory.Delete(GetFullPath(path), recursive);
+ Directory.Delete(fullPath, recursive);
}
catch (DirectoryNotFoundException ex)
{
@@ -80,7 +103,8 @@ namespace Umbraco.Core.IO
public bool DirectoryExists(string path)
{
- return Directory.Exists(GetFullPath(path));
+ var fullPath = GetFullPath(path);
+ return Directory.Exists(fullPath);
}
public void AddFile(string path, Stream stream)
@@ -90,17 +114,17 @@ namespace Umbraco.Core.IO
public void AddFile(string path, Stream stream, bool overrideIfExists)
{
- var fsRelativePath = GetRelativePath(path);
+ var fullPath = GetFullPath(path);
+ var exists = File.Exists(fullPath);
+ if (exists && overrideIfExists == false)
+ throw new InvalidOperationException(string.Format("A file at path '{0}' already exists", path));
- var exists = FileExists(fsRelativePath);
- if (exists && overrideIfExists == false) throw new InvalidOperationException(string.Format("A file at path '{0}' already exists", path));
-
- EnsureDirectory(Path.GetDirectoryName(fsRelativePath));
+ Directory.CreateDirectory(Path.GetDirectoryName(fullPath)); // ensure it exists
if (stream.CanSeek)
stream.Seek(0, 0);
- using (var destination = (Stream)File.Create(GetFullPath(fsRelativePath)))
+ using (var destination = (Stream)File.Create(fullPath))
stream.CopyTo(destination);
}
@@ -111,9 +135,7 @@ namespace Umbraco.Core.IO
public IEnumerable GetFiles(string path, string filter)
{
- var fsRelativePath = GetRelativePath(path);
-
- var fullPath = EnsureTrailingSeparator(GetFullPath(fsRelativePath));
+ var fullPath = GetFullPath(path);
try
{
@@ -140,12 +162,13 @@ namespace Umbraco.Core.IO
public void DeleteFile(string path)
{
- if (!FileExists(path))
+ var fullPath = GetFullPath(path);
+ if (File.Exists(fullPath) == false)
return;
try
{
- File.Delete(GetFullPath(path));
+ File.Delete(fullPath);
}
catch (FileNotFoundException ex)
{
@@ -155,39 +178,86 @@ namespace Umbraco.Core.IO
public bool FileExists(string path)
{
- return File.Exists(GetFullPath(path));
+ var fullpath = GetFullPath(path);
+ return File.Exists(fullpath);
}
+ // beware, many things depend on how the GetRelative/AbsolutePath methods work!
+
+ ///
+ /// Gets the relative path.
+ ///
+ /// The full path or url.
+ /// The path, relative to this filesystem's root.
+ ///
+ /// The relative path is relative to this filesystem's root, not starting with any
+ /// directory separator. If input was recognized as a url (path), then output uses url (path) separator
+ /// chars.
+ ///
public string GetRelativePath(string fullPathOrUrl)
{
- var relativePath = fullPathOrUrl
- .TrimStart(_rootUrl)
- .Replace('/', Path.DirectorySeparatorChar)
- .TrimStart(RootPath)
- .TrimStart(Path.DirectorySeparatorChar);
+ // test url
+ var path = fullPathOrUrl.Replace('\\', '/'); // ensure url separator char
- return relativePath;
+ if (IOHelper.PathStartsWith(path, _rootUrl, '/')) // if it starts with the root url...
+ return path.Substring(_rootUrl.Length) // strip it
+ .TrimStart('/'); // it's relative
+
+ // test path
+ path = EnsureDirectorySeparatorChar(fullPathOrUrl);
+
+ if (IOHelper.PathStartsWith(path, _rootPath, Path.DirectorySeparatorChar)) // if it starts with the root path
+ return path.Substring(_rootPath.Length) // strip it
+ .TrimStart(Path.DirectorySeparatorChar); // it's relative
+
+ // unchanged - including separators
+ return fullPathOrUrl;
}
+ ///
+ /// Gets the full path.
+ ///
+ /// The full or relative path.
+ /// The full path.
+ ///
+ /// On the physical filesystem, the full path is the rooted (ie non-relative), safe (ie within this
+ /// filesystem's root) path. All separators are converted to Path.DirectorySeparatorChar.
+ ///
public string GetFullPath(string path)
{
- //if the path starts with a '/' then it's most likely not a FS relative path which is required so convert it
- if (path.StartsWith("/"))
- {
- path = GetRelativePath(path);
- }
+ // normalize
+ var opath = path;
+ path = EnsureDirectorySeparatorChar(path);
- return !path.StartsWith(RootPath)
- ? Path.Combine(RootPath, path)
- : path;
+ // not sure what we are doing here - so if input starts with a (back) slash,
+ // we assume it's not a FS relative path and we try to convert it... but it
+ // really makes little sense?
+ if (path.StartsWith(Path.DirectorySeparatorChar.ToString()))
+ path = GetRelativePath(path);
+
+ // if already a full path, return
+ if (IOHelper.PathStartsWith(path, _rootPath, Path.DirectorySeparatorChar))
+ return path;
+
+ // else combine and sanitize, ie GetFullPath will take care of any relative
+ // segments in path, eg '../../foo.tmp' - it may throw a SecurityException
+ // if the combined path reaches illegal parts of the filesystem
+ var fpath = Path.Combine(_rootPath, path);
+ fpath = Path.GetFullPath(fpath);
+
+ // at that point, path is within legal parts of the filesystem, ie we have
+ // permissions to reach that path, but it may nevertheless be outside of
+ // our root path, due to relative segments, so better check
+ if (IOHelper.PathStartsWith(fpath, _rootPath, Path.DirectorySeparatorChar))
+ return fpath;
+
+ throw new FileSecurityException("File '" + opath + "' is outside this filesystem's root.");
}
public string GetUrl(string path)
{
- return _rootUrl.TrimEnd("/") + "/" + path
- .TrimStart(Path.DirectorySeparatorChar)
- .Replace(Path.DirectorySeparatorChar, '/')
- .TrimEnd("/");
+ path = EnsureUrlSeparatorChar(path).Trim('/');
+ return _rootUrl + "/" + path;
}
public DateTimeOffset GetLastModified(string path)
@@ -214,9 +284,19 @@ namespace Umbraco.Core.IO
protected string EnsureTrailingSeparator(string path)
{
- if (!path.EndsWith(Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal))
- path = path + Path.DirectorySeparatorChar;
+ return path.EnsureEndsWith(Path.DirectorySeparatorChar);
+ }
+ protected string EnsureDirectorySeparatorChar(string path)
+ {
+ path = path.Replace('/', Path.DirectorySeparatorChar);
+ path = path.Replace('\\', Path.DirectorySeparatorChar);
+ return path;
+ }
+
+ protected string EnsureUrlSeparatorChar(string path)
+ {
+ path = path.Replace('\\', '/');
return path;
}
diff --git a/src/Umbraco.Core/Logging/ParallelForwardingAppender.cs b/src/Umbraco.Core/Logging/ParallelForwardingAppender.cs
index 92c4f7589b..cf7efdb4c4 100644
--- a/src/Umbraco.Core/Logging/ParallelForwardingAppender.cs
+++ b/src/Umbraco.Core/Logging/ParallelForwardingAppender.cs
@@ -22,8 +22,8 @@ namespace Umbraco.Core.Logging
private CancellationTokenSource _loggingCancelationTokenSource;
private CancellationToken _loggingCancelationToken;
private Task _loggingTask;
- private Double _shutdownFlushTimeout = 5;
- private TimeSpan _shutdownFlushTimespan = TimeSpan.FromSeconds(5);
+ private Double _shutdownFlushTimeout = 1;
+ private TimeSpan _shutdownFlushTimespan = TimeSpan.FromSeconds(1);
private static readonly Type ThisType = typeof(ParallelForwardingAppender);
private volatile bool _shutDownRequested;
private int? _bufferSize = DefaultBufferSize;
diff --git a/src/Umbraco.Core/Manifest/ManifestParser.cs b/src/Umbraco.Core/Manifest/ManifestParser.cs
index 571c916123..e30d188339 100644
--- a/src/Umbraco.Core/Manifest/ManifestParser.cs
+++ b/src/Umbraco.Core/Manifest/ManifestParser.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Text;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -140,11 +141,22 @@ namespace Umbraco.Core.Manifest
{
var result = new List();
foreach (var m in manifestFileContents)
- {
- if (m.IsNullOrWhiteSpace()) continue;
+ {
+ var manifestContent = m;
+
+ if (manifestContent.IsNullOrWhiteSpace()) continue;
+
+ // Strip byte object marker, JSON.NET does not like it
+ var preamble = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
+
+ // Strangely StartsWith(preamble) would always return true
+ if (manifestContent.Substring(0, 1) == preamble)
+ manifestContent = manifestContent.Remove(0, preamble.Length);
+
+ if (manifestContent.IsNullOrWhiteSpace()) continue;
//remove any comments first
- var replaced = CommentsSurround.Replace(m, match => " ");
+ var replaced = CommentsSurround.Replace(manifestContent, match => " ");
replaced = CommentsLine.Replace(replaced, match => "");
JObject deserialized;
@@ -154,7 +166,7 @@ namespace Umbraco.Core.Manifest
}
catch (Exception ex)
{
- LogHelper.Error("An error occurred parsing manifest with contents: " + m, ex);
+ LogHelper.Error("An error occurred parsing manifest with contents: " + manifestContent, ex);
continue;
}
diff --git a/src/Umbraco.Core/Models/File.cs b/src/Umbraco.Core/Models/File.cs
index ae4aac6a1c..8ead6da5f8 100644
--- a/src/Umbraco.Core/Models/File.cs
+++ b/src/Umbraco.Core/Models/File.cs
@@ -2,6 +2,8 @@
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
+using System.Text;
+using Umbraco.Core.IO;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
@@ -15,12 +17,20 @@ namespace Umbraco.Core.Models
{
private string _path;
private string _originalPath;
- private string _content = string.Empty; //initialize to empty string, not null
- protected File(string path)
+ // initialize to string.Empty so that it is possible to save a new file,
+ // should use the lazyContent ctor to set it to null when loading existing.
+ // cannot simply use HasIdentity as some classes (eg Script) override it
+ // in a weird way.
+ private string _content;
+ internal Func GetFileContent { get; set; }
+
+ protected File(string path, Func getFileContent = null)
{
- _path = path;
+ _path = SanitizePath(path);
_originalPath = _path;
+ GetFileContent = getFileContent;
+ _content = getFileContent != null ? null : string.Empty;
}
private static readonly PropertyInfo ContentSelector = ExpressionHelper.GetPropertyInfo(x => x.Content);
@@ -28,6 +38,14 @@ namespace Umbraco.Core.Models
private string _alias;
private string _name;
+ private static string SanitizePath(string path)
+ {
+ return path
+ .Replace('\\', System.IO.Path.DirectorySeparatorChar)
+ .Replace('/', System.IO.Path.DirectorySeparatorChar);
+ //.TrimStart(System.IO.Path.DirectorySeparatorChar);
+ }
+
///
/// Gets or sets the Name of the File including extension
///
@@ -71,7 +89,7 @@ namespace Umbraco.Core.Models
SetPropertyValueAndDetectChanges(o =>
{
- _path = value;
+ _path = SanitizePath(value);
return _path;
}, _path, PathSelector);
}
@@ -96,15 +114,26 @@ namespace Umbraco.Core.Models
///
/// Gets or sets the Content of a File
///
+ /// Marked as DoNotClone, because it should be lazy-reloaded from disk.
[DataMember]
+ [DoNotClone]
public virtual string Content
{
- get { return _content; }
+ get
+ {
+ if (_content != null)
+ return _content;
+
+ // else, must lazy-load, and ensure it's not null
+ if (GetFileContent != null)
+ _content = GetFileContent(this);
+ return _content ?? (_content = string.Empty);
+ }
set
{
SetPropertyValueAndDetectChanges(o =>
{
- _content = value;
+ _content = value ?? string.Empty; // cannot set to null
return _content;
}, _content, ContentSelector);
}
@@ -121,17 +150,32 @@ namespace Umbraco.Core.Models
return true;
}
+ // this exists so that class that manage name and alias differently, eg Template,
+ // can implement their own cloning - (though really, not sure it's even needed)
+ protected virtual void DeepCloneNameAndAlias(File clone)
+ {
+ // set fields that have a lazy value, by forcing evaluation of the lazy
+ clone._name = Name;
+ clone._alias = Alias;
+ }
+
public override object DeepClone()
{
- var clone = (File)base.DeepClone();
- //turn off change tracking
+ var clone = (File) base.DeepClone();
+
+ // clear fields that were memberwise-cloned and that we don't want to clone
+ clone._content = null;
+
+ // turn off change tracking
clone.DisableChangeTracking();
- //need to manually assign since they are readonly properties
- clone._alias = Alias;
- clone._name = Name;
- //this shouldn't really be needed since we're not tracking
+
+ // ...
+ DeepCloneNameAndAlias(clone);
+
+ // this shouldn't really be needed since we're not tracking
clone.ResetDirtyProperties(false);
- //re-enable tracking
+
+ // re-enable tracking
clone.EnableChangeTracking();
return clone;
diff --git a/src/Umbraco.Core/Models/IPublishedContentWithKey.cs b/src/Umbraco.Core/Models/IPublishedContentWithKey.cs
new file mode 100644
index 0000000000..b0e71221b2
--- /dev/null
+++ b/src/Umbraco.Core/Models/IPublishedContentWithKey.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Umbraco.Core.Models
+{
+ ///
+ /// Represents a cached content with a GUID key.
+ ///
+ /// This is temporary, because we cannot add the Key property to IPublishedContent without
+ /// breaking backward compatibility. With v8, it will be merged into IPublishedContent.
+ public interface IPublishedContentWithKey : IPublishedContent
+ {
+ Guid Key { get; }
+ }
+}
diff --git a/src/Umbraco.Core/Models/IServerRegistration.cs b/src/Umbraco.Core/Models/IServerRegistration.cs
index 9eb6815bbe..8053ea0a6e 100644
--- a/src/Umbraco.Core/Models/IServerRegistration.cs
+++ b/src/Umbraco.Core/Models/IServerRegistration.cs
@@ -18,6 +18,11 @@ namespace Umbraco.Core.Models
///
bool IsActive { get; set; }
+ ///
+ /// Gets or sets a value indicating whether the server is master.
+ ///
+ bool IsMaster { get; set; }
+
///
/// Gets the date and time the registration was created.
///
diff --git a/src/Umbraco.Core/Models/PartialView.cs b/src/Umbraco.Core/Models/PartialView.cs
index d483de4176..75914820f0 100644
--- a/src/Umbraco.Core/Models/PartialView.cs
+++ b/src/Umbraco.Core/Models/PartialView.cs
@@ -1,9 +1,6 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Runtime.Serialization;
-using System.Text.RegularExpressions;
-using Umbraco.Core.IO;
+using Umbraco.Core.Services;
namespace Umbraco.Core.Models
{
@@ -15,12 +12,14 @@ namespace Umbraco.Core.Models
[DataContract(IsReference = true)]
public class PartialView : File, IPartialView
{
-
public PartialView(string path)
- : base(path)
- {
- base.Path = path;
- }
+ : this(path, null)
+ { }
+ internal PartialView(string path, Func getFileContent)
+ : base(path, getFileContent)
+ { }
+
+ internal PartialViewType ViewType { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Models/PartialViewType.cs b/src/Umbraco.Core/Models/PartialViewType.cs
new file mode 100644
index 0000000000..2b45448271
--- /dev/null
+++ b/src/Umbraco.Core/Models/PartialViewType.cs
@@ -0,0 +1,9 @@
+namespace Umbraco.Core.Models
+{
+ internal enum PartialViewType : byte
+ {
+ Unknown = 0, // default
+ PartialView = 1,
+ PartialViewMacro = 2
+ }
+}
diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentExtended.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentExtended.cs
index 8c0eeef86f..fef066e0b1 100644
--- a/src/Umbraco.Core/Models/PublishedContent/PublishedContentExtended.cs
+++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentExtended.cs
@@ -62,9 +62,20 @@ namespace Umbraco.Core.Models.PublishedContent
// model and therefore returned the original content unchanged.
var model = content.CreateModel();
- var extended = model == content // == means the factory did not create a model
- ? new PublishedContentExtended(content) // so we have to extend
- : model; // else we can use what the factory returned
+ IPublishedContent extended;
+ if (model == content) // == means the factory did not create a model
+ {
+ // so we have to extend
+ var contentWithKey = content as IPublishedContentWithKey;
+ extended = contentWithKey == null
+ ? new PublishedContentExtended(content)
+ : new PublishedContentWithKeyExtended(contentWithKey);
+ }
+ else
+ {
+ // else we can use what the factory returned
+ extended = model;
+ }
// so extended should always implement IPublishedContentExtended, however if
// by mistake the factory returned a different object that does not implement
diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentWithKeyExtended.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentWithKeyExtended.cs
new file mode 100644
index 0000000000..492fd79796
--- /dev/null
+++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentWithKeyExtended.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Umbraco.Core.Models.PublishedContent
+{
+ public class PublishedContentWithKeyExtended : PublishedContentExtended, IPublishedContentWithKey
+ {
+ // protected for models, internal for PublishedContentExtended static Extend method
+ protected internal PublishedContentWithKeyExtended(IPublishedContentWithKey content)
+ : base(content)
+ { }
+
+ public Guid Key { get { return ((IPublishedContentWithKey) Content).Key; } }
+ }
+}
diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentWithKeyModel.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentWithKeyModel.cs
new file mode 100644
index 0000000000..4761a52617
--- /dev/null
+++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentWithKeyModel.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Umbraco.Core.Models.PublishedContent
+{
+ public abstract class PublishedContentWithKeyModel : PublishedContentModel, IPublishedContentWithKey
+ {
+ protected PublishedContentWithKeyModel(IPublishedContentWithKey content)
+ : base (content)
+ { }
+
+ public Guid Key { get { return ((IPublishedContentWithKey) Content).Key; } }
+ }
+}
diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentWithKeyWrapped.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentWithKeyWrapped.cs
new file mode 100644
index 0000000000..35d7dd6f1f
--- /dev/null
+++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentWithKeyWrapped.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Umbraco.Core.Models.PublishedContent
+{
+ ///
+ /// Provides an abstract base class for IPublishedContentWithKey implementations that
+ /// wrap and extend another IPublishedContentWithKey.
+ ///
+ public class PublishedContentWithKeyWrapped : PublishedContentWrapped, IPublishedContentWithKey
+ {
+ protected PublishedContentWithKeyWrapped(IPublishedContentWithKey content)
+ : base(content)
+ { }
+
+ public virtual Guid Key { get { return ((IPublishedContentWithKey) Content).Key; } }
+ }
+}
diff --git a/src/Umbraco.Core/Models/Rdbms/AccessDto.cs b/src/Umbraco.Core/Models/Rdbms/AccessDto.cs
index ba2cb6d767..37b1dbddd8 100644
--- a/src/Umbraco.Core/Models/Rdbms/AccessDto.cs
+++ b/src/Umbraco.Core/Models/Rdbms/AccessDto.cs
@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Security.AccessControl;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Models.Rdbms
{
@@ -30,11 +31,11 @@ namespace Umbraco.Core.Models.Rdbms
public int NoAccessNodeId { get; set; }
[Column("createDate")]
- [Constraint(Default = "getdate()")]
+ [Constraint(Default = SystemMethods.CurrentDateTime)]
public DateTime CreateDate { get; set; }
[Column("updateDate")]
- [Constraint(Default = "getdate()")]
+ [Constraint(Default = SystemMethods.CurrentDateTime)]
public DateTime UpdateDate { get; set; }
[ResultColumn]
diff --git a/src/Umbraco.Core/Models/Rdbms/AccessRuleDto.cs b/src/Umbraco.Core/Models/Rdbms/AccessRuleDto.cs
index a98dfb9450..78e3444e56 100644
--- a/src/Umbraco.Core/Models/Rdbms/AccessRuleDto.cs
+++ b/src/Umbraco.Core/Models/Rdbms/AccessRuleDto.cs
@@ -1,6 +1,7 @@
using System;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Models.Rdbms
{
@@ -25,11 +26,11 @@ namespace Umbraco.Core.Models.Rdbms
public string RuleType { get; set; }
[Column("createDate")]
- [Constraint(Default = "getdate()")]
+ [Constraint(Default = SystemMethods.CurrentDateTime)]
public DateTime CreateDate { get; set; }
[Column("updateDate")]
- [Constraint(Default = "getdate()")]
+ [Constraint(Default = SystemMethods.CurrentDateTime)]
public DateTime UpdateDate { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Models/Rdbms/ContentVersionDto.cs b/src/Umbraco.Core/Models/Rdbms/ContentVersionDto.cs
index 9b1fa02dae..3bd85cccf6 100644
--- a/src/Umbraco.Core/Models/Rdbms/ContentVersionDto.cs
+++ b/src/Umbraco.Core/Models/Rdbms/ContentVersionDto.cs
@@ -1,6 +1,7 @@
using System;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Models.Rdbms
{
@@ -23,7 +24,7 @@ namespace Umbraco.Core.Models.Rdbms
public Guid VersionId { get; set; }
[Column("VersionDate")]
- [Constraint(Default = "getdate()")]
+ [Constraint(Default = SystemMethods.CurrentDateTime)]
public DateTime VersionDate { get; set; }
[ResultColumn]
diff --git a/src/Umbraco.Core/Models/Rdbms/DocumentDto.cs b/src/Umbraco.Core/Models/Rdbms/DocumentDto.cs
index de087667b2..88e04087c9 100644
--- a/src/Umbraco.Core/Models/Rdbms/DocumentDto.cs
+++ b/src/Umbraco.Core/Models/Rdbms/DocumentDto.cs
@@ -1,6 +1,7 @@
using System;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Models.Rdbms
{
@@ -38,7 +39,7 @@ namespace Umbraco.Core.Models.Rdbms
public DateTime? ExpiresDate { get; set; }
[Column("updateDate")]
- [Constraint(Default = "getdate()")]
+ [Constraint(Default = SystemMethods.CurrentDateTime)]
public DateTime UpdateDate { get; set; }
[Column("templateId")]
diff --git a/src/Umbraco.Core/Models/Rdbms/ExternalLoginDto.cs b/src/Umbraco.Core/Models/Rdbms/ExternalLoginDto.cs
index 652c9df714..803c25fdfc 100644
--- a/src/Umbraco.Core/Models/Rdbms/ExternalLoginDto.cs
+++ b/src/Umbraco.Core/Models/Rdbms/ExternalLoginDto.cs
@@ -1,6 +1,7 @@
using System;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Models.Rdbms
{
@@ -27,7 +28,7 @@ namespace Umbraco.Core.Models.Rdbms
public string ProviderKey { get; set; }
[Column("createDate")]
- [Constraint(Default = "getdate()")]
+ [Constraint(Default = SystemMethods.CurrentDateTime)]
public DateTime CreateDate { get; set; }
diff --git a/src/Umbraco.Core/Models/Rdbms/LogDto.cs b/src/Umbraco.Core/Models/Rdbms/LogDto.cs
index 3c2a6a61a5..be67b5873a 100644
--- a/src/Umbraco.Core/Models/Rdbms/LogDto.cs
+++ b/src/Umbraco.Core/Models/Rdbms/LogDto.cs
@@ -1,6 +1,7 @@
using System;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Models.Rdbms
{
@@ -21,7 +22,7 @@ namespace Umbraco.Core.Models.Rdbms
public int NodeId { get; set; }
[Column("Datestamp")]
- [Constraint(Default = "getdate()")]
+ [Constraint(Default = SystemMethods.CurrentDateTime)]
public DateTime Datestamp { get; set; }
[Column("logHeader")]
diff --git a/src/Umbraco.Core/Models/Rdbms/MigrationDto.cs b/src/Umbraco.Core/Models/Rdbms/MigrationDto.cs
index ffd000278d..5ab339fe01 100644
--- a/src/Umbraco.Core/Models/Rdbms/MigrationDto.cs
+++ b/src/Umbraco.Core/Models/Rdbms/MigrationDto.cs
@@ -1,6 +1,7 @@
using System;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Models.Rdbms
{
@@ -19,7 +20,7 @@ namespace Umbraco.Core.Models.Rdbms
public string Name { get; set; }
[Column("createDate")]
- [Constraint(Default = "getdate()")]
+ [Constraint(Default = SystemMethods.CurrentDateTime)]
public DateTime CreateDate { get; set; }
[Column("version")]
diff --git a/src/Umbraco.Core/Models/Rdbms/NodeDto.cs b/src/Umbraco.Core/Models/Rdbms/NodeDto.cs
index d7a859ef06..7003c58e77 100644
--- a/src/Umbraco.Core/Models/Rdbms/NodeDto.cs
+++ b/src/Umbraco.Core/Models/Rdbms/NodeDto.cs
@@ -1,6 +1,7 @@
using System;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Models.Rdbms
{
@@ -48,7 +49,7 @@ namespace Umbraco.Core.Models.Rdbms
[Column("uniqueID")]
[NullSetting(NullSetting = NullSettings.NotNull)]
[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoNodeUniqueID")]
- [Constraint(Default = "newid()")]
+ [Constraint(Default = SystemMethods.NewGuid)]
public Guid UniqueId { get; set; }
[Column("text")]
@@ -61,7 +62,7 @@ namespace Umbraco.Core.Models.Rdbms
public Guid? NodeObjectType { get; set; }
[Column("createDate")]
- [Constraint(Default = "getdate()")]
+ [Constraint(Default = SystemMethods.CurrentDateTime)]
public DateTime CreateDate { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Models/Rdbms/PropertyTypeDto.cs b/src/Umbraco.Core/Models/Rdbms/PropertyTypeDto.cs
index 621ace555b..74a6d34289 100644
--- a/src/Umbraco.Core/Models/Rdbms/PropertyTypeDto.cs
+++ b/src/Umbraco.Core/Models/Rdbms/PropertyTypeDto.cs
@@ -1,6 +1,7 @@
using System;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Models.Rdbms
{
@@ -61,7 +62,7 @@ namespace Umbraco.Core.Models.Rdbms
[Column("UniqueID")]
[NullSetting(NullSetting = NullSettings.NotNull)]
- [Constraint(Default = "newid()")]
+ [Constraint(Default = SystemMethods.NewGuid)]
[Index(IndexTypes.UniqueNonClustered, Name = "IX_cmsPropertyTypeUniqueID")]
public Guid UniqueId { get; set; }
}
diff --git a/src/Umbraco.Core/Models/Rdbms/RelationDto.cs b/src/Umbraco.Core/Models/Rdbms/RelationDto.cs
index e204e42040..368904a5cb 100644
--- a/src/Umbraco.Core/Models/Rdbms/RelationDto.cs
+++ b/src/Umbraco.Core/Models/Rdbms/RelationDto.cs
@@ -1,6 +1,7 @@
using System;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Models.Rdbms
{
@@ -26,7 +27,7 @@ namespace Umbraco.Core.Models.Rdbms
public int RelationType { get; set; }
[Column("datetime")]
- [Constraint(Default = "getdate()")]
+ [Constraint(Default = SystemMethods.CurrentDateTime)]
public DateTime Datetime { get; set; }
[Column("comment")]
diff --git a/src/Umbraco.Core/Models/Rdbms/ServerRegistrationDto.cs b/src/Umbraco.Core/Models/Rdbms/ServerRegistrationDto.cs
index b7bdf265ce..2a3751c083 100644
--- a/src/Umbraco.Core/Models/Rdbms/ServerRegistrationDto.cs
+++ b/src/Umbraco.Core/Models/Rdbms/ServerRegistrationDto.cs
@@ -1,6 +1,7 @@
using System;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Models.Rdbms
{
@@ -23,7 +24,7 @@ namespace Umbraco.Core.Models.Rdbms
public string ServerIdentity { get; set; }
[Column("registeredDate")]
- [Constraint(Default = "getdate()")]
+ [Constraint(Default = SystemMethods.CurrentDateTime)]
public DateTime DateRegistered { get; set; }
[Column("lastNotifiedDate")]
@@ -33,6 +34,7 @@ namespace Umbraco.Core.Models.Rdbms
[Index(IndexTypes.NonClustered)]
public bool IsActive { get; set; }
-
+ [Column("isMaster")]
+ public bool IsMaster { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Models/Rdbms/TaskDto.cs b/src/Umbraco.Core/Models/Rdbms/TaskDto.cs
index 75e4d25cb7..e27f7c0a93 100644
--- a/src/Umbraco.Core/Models/Rdbms/TaskDto.cs
+++ b/src/Umbraco.Core/Models/Rdbms/TaskDto.cs
@@ -1,6 +1,7 @@
using System;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Models.Rdbms
{
@@ -34,7 +35,7 @@ namespace Umbraco.Core.Models.Rdbms
public int UserId { get; set; }
[Column("DateTime")]
- [Constraint(Default = "getdate()")]
+ [Constraint(Default = SystemMethods.CurrentDateTime)]
public DateTime DateTime { get; set; }
[Column("Comment")]
diff --git a/src/Umbraco.Core/Models/Script.cs b/src/Umbraco.Core/Models/Script.cs
index 71f0684447..325885d9ba 100644
--- a/src/Umbraco.Core/Models/Script.cs
+++ b/src/Umbraco.Core/Models/Script.cs
@@ -1,7 +1,5 @@
using System;
-using System.Linq;
using System.Runtime.Serialization;
-using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
@@ -15,16 +13,17 @@ namespace Umbraco.Core.Models
public class Script : File
{
public Script(string path)
- : base(path)
- {
-
- }
+ : this(path, (Func) null)
+ { }
+
+ internal Script(string path, Func getFileContent)
+ : base(path, getFileContent)
+ { }
[Obsolete("This is no longer used and will be removed from the codebase in future versions")]
public Script(string path, IContentSection contentConfig)
- : this(path)
- {
- }
+ : base(path)
+ { }
///
/// Indicates whether the current entity has an identity, which in this case is a path/name.
diff --git a/src/Umbraco.Core/Models/ServerRegistration.cs b/src/Umbraco.Core/Models/ServerRegistration.cs
index 9a871859b6..cee70893d0 100644
--- a/src/Umbraco.Core/Models/ServerRegistration.cs
+++ b/src/Umbraco.Core/Models/ServerRegistration.cs
@@ -2,7 +2,6 @@
using System.Globalization;
using System.Reflection;
using Umbraco.Core.Models.EntityBase;
-using Umbraco.Core.Sync;
namespace Umbraco.Core.Models
{
@@ -14,10 +13,12 @@ namespace Umbraco.Core.Models
private string _serverAddress;
private string _serverIdentity;
private bool _isActive;
+ private bool _isMaster;
private static readonly PropertyInfo ServerAddressSelector = ExpressionHelper.GetPropertyInfo(x => x.ServerAddress);
private static readonly PropertyInfo ServerIdentitySelector = ExpressionHelper.GetPropertyInfo(x => x.ServerIdentity);
private static readonly PropertyInfo IsActiveSelector = ExpressionHelper.GetPropertyInfo(x => x.IsActive);
+ private static readonly PropertyInfo IsMasterSelector = ExpressionHelper.GetPropertyInfo(x => x.IsMaster);
///
/// Initialiazes a new instance of the class.
@@ -34,7 +35,8 @@ namespace Umbraco.Core.Models
/// The date and time the registration was created.
/// The date and time the registration was last accessed.
/// A value indicating whether the registration is active.
- public ServerRegistration(int id, string serverAddress, string serverIdentity, DateTime registered, DateTime accessed, bool isActive)
+ /// A value indicating whether the registration is master.
+ public ServerRegistration(int id, string serverAddress, string serverIdentity, DateTime registered, DateTime accessed, bool isActive, bool isMaster)
{
UpdateDate = accessed;
CreateDate = registered;
@@ -43,6 +45,7 @@ namespace Umbraco.Core.Models
ServerAddress = serverAddress;
ServerIdentity = serverIdentity;
IsActive = isActive;
+ IsMaster = isMaster;
}
///
@@ -108,6 +111,22 @@ namespace Umbraco.Core.Models
}
}
+ ///
+ /// Gets or sets a value indicating whether the server is master.
+ ///
+ public bool IsMaster
+ {
+ get { return _isMaster; }
+ set
+ {
+ SetPropertyValueAndDetectChanges(o =>
+ {
+ _isMaster = value;
+ return _isMaster;
+ }, _isMaster, IsMasterSelector);
+ }
+ }
+
///
/// Gets the date and time the registration was created.
///
@@ -124,7 +143,7 @@ namespace Umbraco.Core.Models
///
public override string ToString()
{
- return string.Format("{{\"{0}\", \"{1}\", {2}active}}", ServerAddress, ServerIdentity, IsActive ? "" : "!");
+ return string.Format("{{\"{0}\", \"{1}\", {2}active, {3}master}}", ServerAddress, ServerIdentity, IsActive ? "" : "!", IsMaster ? "" : "!");
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Models/Stylesheet.cs b/src/Umbraco.Core/Models/Stylesheet.cs
index ca203d835d..060246df54 100644
--- a/src/Umbraco.Core/Models/Stylesheet.cs
+++ b/src/Umbraco.Core/Models/Stylesheet.cs
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Runtime.Serialization;
-using System.Text;
using Umbraco.Core.IO;
using Umbraco.Core.Strings.Css;
@@ -16,12 +16,16 @@ namespace Umbraco.Core.Models
[DataContract(IsReference = true)]
public class Stylesheet : File
{
- public Stylesheet(string path)
- : base(path.EnsureEndsWith(".css"))
- {
+ public Stylesheet(string path)
+ : this(path, null)
+ { }
+
+ internal Stylesheet(string path, Func getFileContent)
+ : base(path.EnsureEndsWith(".css"), getFileContent)
+ {
InitializeProperties();
}
-
+
private Lazy> _properties;
private void InitializeProperties()
@@ -81,7 +85,7 @@ namespace Umbraco.Core.Models
///
///
///
- void Property_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
+ void Property_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
var prop = (StylesheetProperty) sender;
diff --git a/src/Umbraco.Core/Models/Template.cs b/src/Umbraco.Core/Models/Template.cs
index 3a8cbf8794..4aca88f286 100644
--- a/src/Umbraco.Core/Models/Template.cs
+++ b/src/Umbraco.Core/Models/Template.cs
@@ -1,7 +1,10 @@
using System;
using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
+using System.Text;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
@@ -29,12 +32,16 @@ namespace Umbraco.Core.Models
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name);
public Template(string name, string alias)
- : base(string.Empty)
+ : this(name, alias, (Func) null)
+ { }
+
+ internal Template(string name, string alias, Func getFileContent)
+ : base(string.Empty, getFileContent)
{
_name = name;
_alias = alias.ToCleanString(CleanStringType.UnderscoreAlias);
_masterTemplateId = new Lazy(() => -1);
- }
+ }
[Obsolete("This constructor should not be used, file path is determined by alias, setting the path here will have no affect")]
public Template(string path, string name, string alias)
@@ -123,7 +130,6 @@ namespace Umbraco.Core.Models
Key = Guid.NewGuid();
}
-
public void SetMasterTemplate(ITemplate masterTemplate)
{
if (masterTemplate == null)
@@ -139,27 +145,9 @@ namespace Umbraco.Core.Models
}
- public override object DeepClone()
+ protected override void DeepCloneNameAndAlias(File clone)
{
-
- //We cannot call in to the base classes to clone because the base File class treats Alias, Name.. differently so we need to manually do the clone
-
- //Memberwise clone on Entity will work since it doesn't have any deep elements
- // for any sub class this will work for standard properties as well that aren't complex object's themselves.
- var clone = (Template)MemberwiseClone();
- //turn off change tracking
- clone.DisableChangeTracking();
- //Automatically deep clone ref properties that are IDeepCloneable
- DeepCloneHelper.DeepCloneRefProperties(this, clone);
-
- //this shouldn't really be needed since we're not tracking
- clone.ResetDirtyProperties(false);
- //re-enable tracking
- clone.EnableChangeTracking();
-
- return clone;
+ // do nothing - prevents File from doing its stuff
}
-
-
}
}
diff --git a/src/Umbraco.Core/Persistence/DatabaseAnnotations/ConstraintAttribute.cs b/src/Umbraco.Core/Persistence/DatabaseAnnotations/ConstraintAttribute.cs
index 599f599f85..33c7616687 100644
--- a/src/Umbraco.Core/Persistence/DatabaseAnnotations/ConstraintAttribute.cs
+++ b/src/Umbraco.Core/Persistence/DatabaseAnnotations/ConstraintAttribute.cs
@@ -20,6 +20,6 @@ namespace Umbraco.Core.Persistence.DatabaseAnnotations
///
/// Gets or sets the Default value
///
- public string Default { get; set; }
+ public object Default { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/SystemMethods.cs b/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/SystemMethods.cs
index b7cacf0899..24c2294b59 100644
--- a/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/SystemMethods.cs
+++ b/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/SystemMethods.cs
@@ -3,8 +3,8 @@ namespace Umbraco.Core.Persistence.DatabaseModelDefinitions
public enum SystemMethods
{
NewGuid,
- NewSequentialId,
CurrentDateTime,
- CurrentUTCDateTime
+ //NewSequentialId,
+ //CurrentUTCDateTime
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/DatabasenodeLockExtensions.cs b/src/Umbraco.Core/Persistence/DatabasenodeLockExtensions.cs
new file mode 100644
index 0000000000..3e6d245416
--- /dev/null
+++ b/src/Umbraco.Core/Persistence/DatabasenodeLockExtensions.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Runtime.CompilerServices;
+
+namespace Umbraco.Core.Persistence
+{
+ internal static class DatabaseNodeLockExtensions
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void ValidateDatabase(UmbracoDatabase database)
+ {
+ if (database == null)
+ throw new ArgumentNullException("database");
+ if (database.CurrentTransactionIsolationLevel < IsolationLevel.RepeatableRead)
+ throw new InvalidOperationException("A transaction with minimum RepeatableRead isolation level is required.");
+ }
+
+ // updating a record within a repeatable-read transaction gets an exclusive lock on
+ // that record which will be kept until the transaction is ended, effectively locking
+ // out all other accesses to that record - thus obtaining an exclusive lock over the
+ // protected resources.
+ public static void AcquireLockNodeWriteLock(this UmbracoDatabase database, int nodeId)
+ {
+ ValidateDatabase(database);
+
+ database.Execute("UPDATE umbracoNode SET sortOrder = (CASE WHEN (sortOrder=1) THEN -1 ELSE 1 END) WHERE id=@id",
+ new { @id = nodeId });
+ }
+
+ // reading a record within a repeatable-read transaction gets a shared lock on
+ // that record which will be kept until the transaction is ended, effectively preventing
+ // other write accesses to that record - thus obtaining a shared lock over the protected
+ // resources.
+ public static void AcquireLockNodeReadLock(this UmbracoDatabase database, int nodeId)
+ {
+ ValidateDatabase(database);
+
+ database.ExecuteScalar("SELECT sortOrder FROM umbracoNode WHERE id=@id",
+ new { @id = nodeId });
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Factories/ServerRegistrationFactory.cs b/src/Umbraco.Core/Persistence/Factories/ServerRegistrationFactory.cs
index 9ecc02e213..9c315aef46 100644
--- a/src/Umbraco.Core/Persistence/Factories/ServerRegistrationFactory.cs
+++ b/src/Umbraco.Core/Persistence/Factories/ServerRegistrationFactory.cs
@@ -7,7 +7,7 @@ namespace Umbraco.Core.Persistence.Factories
{
public ServerRegistration BuildEntity(ServerRegistrationDto dto)
{
- var model = new ServerRegistration(dto.Id, dto.ServerAddress, dto.ServerIdentity, dto.DateRegistered, dto.DateAccessed, dto.IsActive);
+ var model = new ServerRegistration(dto.Id, dto.ServerAddress, dto.ServerIdentity, dto.DateRegistered, dto.DateAccessed, dto.IsActive, dto.IsMaster);
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
model.ResetDirtyProperties(false);
@@ -21,6 +21,7 @@ namespace Umbraco.Core.Persistence.Factories
ServerAddress = entity.ServerAddress,
DateRegistered = entity.CreateDate,
IsActive = entity.IsActive,
+ IsMaster = ((ServerRegistration) entity).IsMaster,
DateAccessed = entity.UpdateDate,
ServerIdentity = entity.ServerIdentity
};
diff --git a/src/Umbraco.Core/Persistence/Factories/TemplateFactory.cs b/src/Umbraco.Core/Persistence/Factories/TemplateFactory.cs
index d1742dc030..60cde916b6 100644
--- a/src/Umbraco.Core/Persistence/Factories/TemplateFactory.cs
+++ b/src/Umbraco.Core/Persistence/Factories/TemplateFactory.cs
@@ -33,9 +33,9 @@ namespace Umbraco.Core.Persistence.Factories
#region Implementation of IEntityFactory
- public Template BuildEntity(TemplateDto dto, IEnumerable childDefinitions)
+ public Template BuildEntity(TemplateDto dto, IEnumerable childDefinitions, Func getFileContent)
{
- var template = new Template(dto.NodeDto.Text, dto.Alias)
+ var template = new Template(dto.NodeDto.Text, dto.Alias, getFileContent)
{
CreateDate = dto.NodeDto.CreateDate,
Id = dto.NodeId,
diff --git a/src/Umbraco.Core/Persistence/LockedRepository.cs b/src/Umbraco.Core/Persistence/LockedRepository.cs
new file mode 100644
index 0000000000..b5d2d672f2
--- /dev/null
+++ b/src/Umbraco.Core/Persistence/LockedRepository.cs
@@ -0,0 +1,27 @@
+using System;
+using Umbraco.Core.Persistence.Repositories;
+using Umbraco.Core.Persistence.UnitOfWork;
+
+namespace Umbraco.Core.Persistence
+{
+ internal class LockedRepository
+ where TRepository : IDisposable, IRepository
+ {
+ public LockedRepository(Transaction transaction, IDatabaseUnitOfWork unitOfWork, TRepository repository)
+ {
+ Transaction = transaction;
+ UnitOfWork = unitOfWork;
+ Repository = repository;
+ }
+
+ public Transaction Transaction { get; private set; }
+ public IDatabaseUnitOfWork UnitOfWork { get; private set; }
+ public TRepository Repository { get; private set; }
+
+ public void Commit()
+ {
+ UnitOfWork.Commit();
+ Transaction.Complete();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/LockingRepository.cs b/src/Umbraco.Core/Persistence/LockingRepository.cs
new file mode 100644
index 0000000000..f513073e71
--- /dev/null
+++ b/src/Umbraco.Core/Persistence/LockingRepository.cs
@@ -0,0 +1,103 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Linq;
+using Umbraco.Core.Persistence.Repositories;
+using Umbraco.Core.Persistence.UnitOfWork;
+
+namespace Umbraco.Core.Persistence
+{
+ internal class LockingRepository
+ where TRepository : IDisposable, IRepository
+ {
+ private readonly IDatabaseUnitOfWorkProvider _uowProvider;
+ private readonly Func _repositoryFactory;
+ private readonly int[] _readLockIds, _writeLockIds;
+
+ public LockingRepository(IDatabaseUnitOfWorkProvider uowProvider, Func repositoryFactory,
+ IEnumerable readLockIds, IEnumerable writeLockIds)
+ {
+ Mandate.ParameterNotNull(uowProvider, "uowProvider");
+ Mandate.ParameterNotNull(repositoryFactory, "repositoryFactory");
+
+ _uowProvider = uowProvider;
+ _repositoryFactory = repositoryFactory;
+ _readLockIds = readLockIds == null ? new int[0] : readLockIds.ToArray();
+ _writeLockIds = writeLockIds == null ? new int[0] : writeLockIds.ToArray();
+ }
+
+ public void WithReadLocked(Action> action, bool autoCommit = true)
+ {
+ var uow = _uowProvider.GetUnitOfWork();
+ using (var transaction = uow.Database.GetTransaction(IsolationLevel.RepeatableRead))
+ {
+ foreach (var lockId in _readLockIds)
+ uow.Database.AcquireLockNodeReadLock(lockId);
+
+ using (var repository = _repositoryFactory(uow))
+ {
+ action(new LockedRepository(transaction, uow, repository));
+ if (autoCommit == false) return;
+ uow.Commit();
+ transaction.Complete();
+ }
+ }
+ }
+
+ public TResult WithReadLocked(Func, TResult> func, bool autoCommit = true)
+ {
+ var uow = _uowProvider.GetUnitOfWork();
+ using (var transaction = uow.Database.GetTransaction(IsolationLevel.RepeatableRead))
+ {
+ foreach (var lockId in _readLockIds)
+ uow.Database.AcquireLockNodeReadLock(lockId);
+
+ using (var repository = _repositoryFactory(uow))
+ {
+ var ret = func(new LockedRepository(transaction, uow, repository));
+ if (autoCommit == false) return ret;
+ uow.Commit();
+ transaction.Complete();
+ return ret;
+ }
+ }
+ }
+
+ public void WithWriteLocked(Action> action, bool autoCommit = true)
+ {
+ var uow = _uowProvider.GetUnitOfWork();
+ using (var transaction = uow.Database.GetTransaction(IsolationLevel.RepeatableRead))
+ {
+ foreach (var lockId in _writeLockIds)
+ uow.Database.AcquireLockNodeWriteLock(lockId);
+
+ using (var repository = _repositoryFactory(uow))
+ {
+ action(new LockedRepository(transaction, uow, repository));
+ if (autoCommit == false) return;
+ uow.Commit();
+ transaction.Complete();
+ }
+ }
+ }
+
+ public TResult WithWriteLocked(Func, TResult> func, bool autoCommit = true)
+ {
+ var uow = _uowProvider.GetUnitOfWork();
+ using (var transaction = uow.Database.GetTransaction(IsolationLevel.RepeatableRead))
+ {
+ foreach (var lockId in _writeLockIds)
+ uow.Database.AcquireLockNodeReadLock(lockId);
+
+ using (var repository = _repositoryFactory(uow))
+ {
+ var ret = func(new LockedRepository(transaction, uow, repository));
+ if (autoCommit == false) return ret;
+ uow.Commit();
+ transaction.Complete();
+ return ret;
+ }
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Persistence/Mappers/ServerRegistrationMapper.cs b/src/Umbraco.Core/Persistence/Mappers/ServerRegistrationMapper.cs
index e532db18aa..54d7e8cdc1 100644
--- a/src/Umbraco.Core/Persistence/Mappers/ServerRegistrationMapper.cs
+++ b/src/Umbraco.Core/Persistence/Mappers/ServerRegistrationMapper.cs
@@ -30,6 +30,7 @@ namespace Umbraco.Core.Persistence.Mappers
{
CacheMap(src => src.Id, dto => dto.Id);
CacheMap(src => src.IsActive, dto => dto.IsActive);
+ CacheMap(src => src.IsMaster, dto => dto.IsMaster);
CacheMap(src => src.ServerAddress, dto => dto.ServerAddress);
CacheMap(src => src.CreateDate, dto => dto.DateRegistered);
CacheMap(src => src.UpdateDate, dto => dto.DateAccessed);
diff --git a/src/Umbraco.Core/Persistence/Migrations/MigrationBase.cs b/src/Umbraco.Core/Persistence/Migrations/MigrationBase.cs
index e37d001fea..a19aaa24ad 100644
--- a/src/Umbraco.Core/Persistence/Migrations/MigrationBase.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/MigrationBase.cs
@@ -16,13 +16,7 @@ namespace Umbraco.Core.Persistence.Migrations
{
public ISqlSyntaxProvider SqlSyntax { get; private set; }
public ILogger Logger { get; private set; }
-
- [Obsolete("Use the other constructor specifying all dependencies instead")]
- protected MigrationBase()
- : this(SqlSyntaxContext.SqlSyntaxProvider, LoggerResolver.Current.Logger)
- {
- }
-
+
protected MigrationBase(ISqlSyntaxProvider sqlSyntax, ILogger logger)
{
SqlSyntax = sqlSyntax;
@@ -48,7 +42,7 @@ namespace Umbraco.Core.Persistence.Migrations
public IAlterSyntaxBuilder Alter
{
- get { return new AlterSyntaxBuilder(Context); }
+ get { return new AlterSyntaxBuilder(Context, SqlSyntax); }
}
public ICreateBuilder Create
@@ -63,27 +57,27 @@ namespace Umbraco.Core.Persistence.Migrations
public IExecuteBuilder Execute
{
- get { return new ExecuteBuilder(Context); }
+ get { return new ExecuteBuilder(Context, SqlSyntax); }
}
public IInsertBuilder Insert
{
- get { return new InsertBuilder(Context); }
+ get { return new InsertBuilder(Context, SqlSyntax); }
}
public IRenameBuilder Rename
{
- get { return new RenameBuilder(Context); }
+ get { return new RenameBuilder(Context, SqlSyntax); }
}
public IUpdateBuilder Update
{
- get { return new UpdateBuilder(Context); }
+ get { return new UpdateBuilder(Context, SqlSyntax); }
}
public IIfDatabaseBuilder IfDatabase(params DatabaseProviders[] databaseProviders)
{
- return new IfDatabaseBuilder(Context, databaseProviders);
+ return new IfDatabaseBuilder(Context, SqlSyntax, databaseProviders);
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Migrations/MigrationExpressionBase.cs b/src/Umbraco.Core/Persistence/Migrations/MigrationExpressionBase.cs
index 7dde31d3e3..35d199d5f0 100644
--- a/src/Umbraco.Core/Persistence/Migrations/MigrationExpressionBase.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/MigrationExpressionBase.cs
@@ -7,22 +7,22 @@ namespace Umbraco.Core.Persistence.Migrations
{
public abstract class MigrationExpressionBase : IMigrationExpression
{
- [Obsolete("Use the other constructors specifying an ISqlSyntaxProvider instead")]
- protected MigrationExpressionBase()
- : this(SqlSyntaxContext.SqlSyntaxProvider)
- {
- }
+ //[Obsolete("Use the other constructors specifying an ISqlSyntaxProvider instead")]
+ //protected MigrationExpressionBase()
+ // : this(SqlSyntaxContext.SqlSyntaxProvider)
+ //{
+ //}
- [Obsolete("Use the other constructors specifying an ISqlSyntaxProvider instead")]
- protected MigrationExpressionBase(DatabaseProviders current, DatabaseProviders[] databaseProviders)
- : this(current, databaseProviders, SqlSyntaxContext.SqlSyntaxProvider)
- {
- }
+ //[Obsolete("Use the other constructors specifying an ISqlSyntaxProvider instead")]
+ //protected MigrationExpressionBase(DatabaseProviders current, DatabaseProviders[] databaseProviders)
+ // : this(current, databaseProviders, SqlSyntaxContext.SqlSyntaxProvider)
+ //{
+ //}
- protected MigrationExpressionBase(ISqlSyntaxProvider sqlSyntax)
- {
- SqlSyntax = sqlSyntax;
- }
+ //protected MigrationExpressionBase(ISqlSyntaxProvider sqlSyntax)
+ //{
+ // SqlSyntax = sqlSyntax;
+ //}
protected MigrationExpressionBase(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
{
@@ -76,8 +76,10 @@ namespace Umbraco.Core.Persistence.Migrations
case TypeCode.UInt32:
case TypeCode.UInt64:
return val.ToString();
+ case TypeCode.DateTime:
+ return SqlSyntax.GetQuotedValue(SqlSyntax.FormatDateTime((DateTime) val));
default:
- return SqlSyntaxContext.SqlSyntaxProvider.GetQuotedValue(val.ToString());
+ return SqlSyntax.GetQuotedValue(val.ToString());
}
}
}
diff --git a/src/Umbraco.Core/Persistence/Migrations/MigrationRunner.cs b/src/Umbraco.Core/Persistence/Migrations/MigrationRunner.cs
index 539b00fe42..234cd67386 100644
--- a/src/Umbraco.Core/Persistence/Migrations/MigrationRunner.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/MigrationRunner.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
+using System.Text;
using log4net;
using Semver;
using Umbraco.Core.Configuration;
@@ -243,13 +245,43 @@ namespace Umbraco.Core.Persistence.Migrations
//TODO: We should output all of these SQL calls to files in a migration folder in App_Data/TEMP
// so if people want to executed them manually on another environment, they can.
- _logger.Info("Executing sql statement " + i + ": " + sql);
- database.Execute(sql);
+ //The following ensures the multiple statement sare executed one at a time, this is a requirement
+ // of SQLCE, it's unfortunate but necessary.
+ // http://stackoverflow.com/questions/13665491/sql-ce-inconsistent-with-multiple-statements
+ var sb = new StringBuilder();
+ using (var reader = new StringReader(sql))
+ {
+ string line;
+ while ((line = reader.ReadLine()) != null)
+ {
+ line = line.Trim();
+ if (line.Equals("GO", StringComparison.OrdinalIgnoreCase))
+ {
+ //Execute the SQL up to the point of a GO statement
+ var exeSql = sb.ToString();
+ _logger.Info("Executing sql statement " + i + ": " + exeSql);
+ database.Execute(exeSql);
+
+ //restart the string builder
+ sb.Remove(0, sb.Length);
+ }
+ else
+ {
+ sb.AppendLine(line);
+ }
+ }
+ //execute anything remaining
+ if (sb.Length > 0)
+ {
+ var exeSql = sb.ToString();
+ _logger.Info("Executing sql statement " + i + ": " + exeSql);
+ database.Execute(exeSql);
+ }
+ }
+
i++;
}
-
-
transaction.Complete();
//Now that this is all complete, we need to add an entry to the migrations table flagging that migrations
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/AlterSyntaxBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/AlterSyntaxBuilder.cs
index 299550d83e..e253f8e607 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/AlterSyntaxBuilder.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/AlterSyntaxBuilder.cs
@@ -1,30 +1,35 @@
using Umbraco.Core.Persistence.Migrations.Syntax.Alter.Column;
using Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions;
using Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table;
+using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter
{
public class AlterSyntaxBuilder : IAlterSyntaxBuilder
{
private readonly IMigrationContext _context;
+ private readonly ISqlSyntaxProvider _sqlSyntax;
+ private readonly DatabaseProviders[] _databaseProviders;
- public AlterSyntaxBuilder(IMigrationContext context)
+ public AlterSyntaxBuilder(IMigrationContext context, ISqlSyntaxProvider sqlSyntax, params DatabaseProviders[] databaseProviders)
{
_context = context;
+ _sqlSyntax = sqlSyntax;
+ _databaseProviders = databaseProviders;
}
public IAlterTableSyntax Table(string tableName)
{
- var expression = new AlterTableExpression { TableName = tableName };
+ var expression = new AlterTableExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax) { TableName = tableName };
//_context.Expressions.Add(expression);
- return new AlterTableBuilder(expression, _context);
+ return new AlterTableBuilder(_context, _databaseProviders, expression);
}
public IAlterColumnSyntax Column(string columnName)
{
- var expression = new AlterColumnExpression { Column = { Name = columnName } };
+ var expression = new AlterColumnExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax) {Column = {Name = columnName}};
//_context.Expressions.Add(expression);
- return new AlterColumnBuilder(expression, _context);
+ return new AlterColumnBuilder(_context, _databaseProviders, expression);
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Column/AlterColumnBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Column/AlterColumnBuilder.cs
index 3b77743b0d..a7077f2d35 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Column/AlterColumnBuilder.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Column/AlterColumnBuilder.cs
@@ -2,6 +2,7 @@
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions;
using Umbraco.Core.Persistence.Migrations.Syntax.Expressions;
+using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Column
{
@@ -11,11 +12,13 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Column
IAlterColumnOptionForeignKeyCascadeSyntax
{
private readonly IMigrationContext _context;
+ private readonly DatabaseProviders[] _databaseProviders;
- public AlterColumnBuilder(AlterColumnExpression expression, IMigrationContext context)
+ public AlterColumnBuilder(IMigrationContext context, DatabaseProviders[] databaseProviders, AlterColumnExpression expression)
: base(expression)
{
_context = context;
+ _databaseProviders = databaseProviders;
}
public ForeignKeyDefinition CurrentForeignKey { get; set; }
@@ -33,7 +36,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Column
public IAlterColumnOptionSyntax WithDefault(SystemMethods method)
{
- var dc = new AlterDefaultConstraintExpression
+ var dc = new AlterDefaultConstraintExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax)
{
TableName = Expression.TableName,
SchemaName = Expression.SchemaName,
@@ -51,7 +54,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Column
public IAlterColumnOptionSyntax WithDefaultValue(object value)
{
- var dc = new AlterDefaultConstraintExpression
+ var dc = new AlterDefaultConstraintExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax)
{
TableName = Expression.TableName,
SchemaName = Expression.SchemaName,
@@ -81,15 +84,12 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Column
{
Expression.Column.IsIndexed = true;
- var index = new CreateIndexExpression
- {
- Index = new IndexDefinition
- {
- Name = indexName,
- SchemaName = Expression.SchemaName,
- TableName = Expression.TableName
- }
- };
+ var index = new CreateIndexExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax, new IndexDefinition
+ {
+ Name = indexName,
+ SchemaName = Expression.SchemaName,
+ TableName = Expression.TableName
+ });
index.Index.Columns.Add(new IndexColumnDefinition
{
@@ -135,16 +135,13 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Column
{
Expression.Column.IsUnique = true;
- var index = new CreateIndexExpression
- {
- Index = new IndexDefinition
- {
- Name = indexName,
- SchemaName = Expression.SchemaName,
- TableName = Expression.TableName,
- IsUnique = true
- }
- };
+ var index = new CreateIndexExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax, new IndexDefinition
+ {
+ Name = indexName,
+ SchemaName = Expression.SchemaName,
+ TableName = Expression.TableName,
+ IsUnique = true
+ });
index.Index.Columns.Add(new IndexColumnDefinition
{
@@ -172,17 +169,14 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Column
{
Expression.Column.IsForeignKey = true;
- var fk = new CreateForeignKeyExpression
- {
- ForeignKey = new ForeignKeyDefinition
- {
- Name = foreignKeyName,
- PrimaryTable = primaryTableName,
- PrimaryTableSchema = primaryTableSchema,
- ForeignTable = Expression.TableName,
- ForeignTableSchema = Expression.SchemaName
- }
- };
+ var fk = new CreateForeignKeyExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax, new ForeignKeyDefinition
+ {
+ Name = foreignKeyName,
+ PrimaryTable = primaryTableName,
+ PrimaryTableSchema = primaryTableSchema,
+ ForeignTable = Expression.TableName,
+ ForeignTableSchema = Expression.SchemaName
+ });
fk.ForeignKey.PrimaryColumns.Add(primaryColumnName);
fk.ForeignKey.ForeignColumns.Add(Expression.Column.Name);
@@ -212,17 +206,14 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Column
public IAlterColumnOptionForeignKeyCascadeSyntax ReferencedBy(string foreignKeyName, string foreignTableSchema,
string foreignTableName, string foreignColumnName)
{
- var fk = new CreateForeignKeyExpression
- {
- ForeignKey = new ForeignKeyDefinition
- {
- Name = foreignKeyName,
- PrimaryTable = Expression.TableName,
- PrimaryTableSchema = Expression.SchemaName,
- ForeignTable = foreignTableName,
- ForeignTableSchema = foreignTableSchema
- }
- };
+ var fk = new CreateForeignKeyExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax, new ForeignKeyDefinition
+ {
+ Name = foreignKeyName,
+ PrimaryTable = Expression.TableName,
+ PrimaryTableSchema = Expression.SchemaName,
+ ForeignTable = foreignTableName,
+ ForeignTableSchema = foreignTableSchema
+ });
fk.ForeignKey.PrimaryColumns.Add(Expression.Column.Name);
fk.ForeignKey.ForeignColumns.Add(foreignColumnName);
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs
index 43be956440..a40e7be320 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs
@@ -6,11 +6,11 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions
{
public class AlterColumnExpression : MigrationExpressionBase
{
- public AlterColumnExpression(ISqlSyntaxProvider sqlSyntax)
- : base(sqlSyntax)
- {
- Column = new ColumnDefinition() { ModificationType = ModificationType.Alter };
- }
+ //public AlterColumnExpression(ISqlSyntaxProvider sqlSyntax)
+ // : base(sqlSyntax)
+ //{
+ // Column = new ColumnDefinition() { ModificationType = ModificationType.Alter };
+ //}
public AlterColumnExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
: base(current, databaseProviders, sqlSyntax)
@@ -18,17 +18,17 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions
Column = new ColumnDefinition() { ModificationType = ModificationType.Alter };
}
- [Obsolete("Use the constructor specifying an ISqlSyntaxProvider instead")]
- public AlterColumnExpression()
- : this(SqlSyntaxContext.SqlSyntaxProvider)
- {
- }
+ //[Obsolete("Use the constructor specifying an ISqlSyntaxProvider instead")]
+ //public AlterColumnExpression()
+ // : this(SqlSyntaxContext.SqlSyntaxProvider)
+ //{
+ //}
- [Obsolete("Use the constructor specifying an ISqlSyntaxProvider instead")]
- public AlterColumnExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders)
- : this(current, databaseProviders, SqlSyntaxContext.SqlSyntaxProvider)
- {
- }
+ //[Obsolete("Use the constructor specifying an ISqlSyntaxProvider instead")]
+ //public AlterColumnExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders)
+ // : this(current, databaseProviders, SqlSyntaxContext.SqlSyntaxProvider)
+ //{
+ //}
@@ -42,9 +42,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions
// SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(Column.Name),
// SqlSyntaxContext.SqlSyntaxProvider.Format(Column));
- return string.Format(SqlSyntaxContext.SqlSyntaxProvider.AlterColumn,
- SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName),
- SqlSyntaxContext.SqlSyntaxProvider.Format(Column));
+ return string.Format(SqlSyntax.AlterColumn,
+ SqlSyntax.GetQuotedTableName(TableName),
+ SqlSyntax.Format(Column));
//return string.Format(SqlSyntaxContext.SqlSyntaxProvider.AlterColumn,
// SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName),
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterDefaultConstraintExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterDefaultConstraintExpression.cs
index cd99b6754f..cd83f55a35 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterDefaultConstraintExpression.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterDefaultConstraintExpression.cs
@@ -4,11 +4,8 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions
{
public class AlterDefaultConstraintExpression : MigrationExpressionBase
{
- public AlterDefaultConstraintExpression()
- {
- }
-
- public AlterDefaultConstraintExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders) : base(current, databaseProviders)
+ public AlterDefaultConstraintExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
+ : base(current, databaseProviders, sqlSyntax)
{
}
@@ -22,9 +19,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions
{
//NOTE Should probably investigate if Deleting a Default Constraint is different from deleting a 'regular' constraint
- return string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteConstraint,
- SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName),
- SqlSyntaxContext.SqlSyntaxProvider.GetQuotedName(ConstraintName));
+ return string.Format(SqlSyntax.DeleteConstraint,
+ SqlSyntax.GetQuotedTableName(TableName),
+ SqlSyntax.GetQuotedName(ConstraintName));
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterTableExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterTableExpression.cs
index 360b699cd8..b5906ed324 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterTableExpression.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterTableExpression.cs
@@ -1,12 +1,12 @@
-namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions
+using Umbraco.Core.Persistence.SqlSyntax;
+
+namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions
{
public class AlterTableExpression : MigrationExpressionBase
{
- public AlterTableExpression()
- {
- }
- public AlterTableExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders) : base(current, databaseProviders)
+ public AlterTableExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
+ : base(current, databaseProviders, sqlSyntax)
{
}
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/AlterTableBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/AlterTableBuilder.cs
index a50e393e96..7a6ab8d47a 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/AlterTableBuilder.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/AlterTableBuilder.cs
@@ -2,6 +2,7 @@
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions;
using Umbraco.Core.Persistence.Migrations.Syntax.Expressions;
+using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table
{
@@ -10,11 +11,13 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table
IAlterTableColumnOptionForeignKeyCascadeSyntax
{
private readonly IMigrationContext _context;
+ private readonly DatabaseProviders[] _databaseProviders;
- public AlterTableBuilder(AlterTableExpression expression, IMigrationContext context)
+ public AlterTableBuilder(IMigrationContext context, DatabaseProviders[] databaseProviders, AlterTableExpression expression)
: base(expression)
{
_context = context;
+ _databaseProviders = databaseProviders;
}
public ColumnDefinition CurrentColumn { get; set; }
@@ -36,7 +39,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table
{
if (CurrentColumn.ModificationType == ModificationType.Alter)
{
- var dc = new AlterDefaultConstraintExpression
+ var dc = new AlterDefaultConstraintExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax)
{
TableName = Expression.TableName,
SchemaName = Expression.SchemaName,
@@ -66,15 +69,12 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table
{
CurrentColumn.IsIndexed = true;
- var index = new CreateIndexExpression
- {
- Index = new IndexDefinition
- {
- Name = indexName,
- SchemaName = Expression.SchemaName,
- TableName = Expression.TableName
- }
- };
+ var index = new CreateIndexExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax, new IndexDefinition
+ {
+ Name = indexName,
+ SchemaName = Expression.SchemaName,
+ TableName = Expression.TableName
+ });
index.Index.Columns.Add(new IndexColumnDefinition
{
@@ -120,16 +120,13 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table
{
CurrentColumn.IsUnique = true;
- var index = new CreateIndexExpression
- {
- Index = new IndexDefinition
- {
- Name = indexName,
- SchemaName = Expression.SchemaName,
- TableName = Expression.TableName,
- IsUnique = true
- }
- };
+ var index = new CreateIndexExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax, new IndexDefinition
+ {
+ Name = indexName,
+ SchemaName = Expression.SchemaName,
+ TableName = Expression.TableName,
+ IsUnique = true
+ });
index.Index.Columns.Add(new IndexColumnDefinition
{
@@ -157,17 +154,14 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table
{
CurrentColumn.IsForeignKey = true;
- var fk = new CreateForeignKeyExpression
- {
- ForeignKey = new ForeignKeyDefinition
- {
- Name = foreignKeyName,
- PrimaryTable = primaryTableName,
- PrimaryTableSchema = primaryTableSchema,
- ForeignTable = Expression.TableName,
- ForeignTableSchema = Expression.SchemaName
- }
- };
+ var fk = new CreateForeignKeyExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax, new ForeignKeyDefinition
+ {
+ Name = foreignKeyName,
+ PrimaryTable = primaryTableName,
+ PrimaryTableSchema = primaryTableSchema,
+ ForeignTable = Expression.TableName,
+ ForeignTableSchema = Expression.SchemaName
+ });
fk.ForeignKey.PrimaryColumns.Add(primaryColumnName);
fk.ForeignKey.ForeignColumns.Add(CurrentColumn.Name);
@@ -197,17 +191,14 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table
public IAlterTableColumnOptionForeignKeyCascadeSyntax ReferencedBy(string foreignKeyName, string foreignTableSchema,
string foreignTableName, string foreignColumnName)
{
- var fk = new CreateForeignKeyExpression
- {
- ForeignKey = new ForeignKeyDefinition
- {
- Name = foreignKeyName,
- PrimaryTable = Expression.TableName,
- PrimaryTableSchema = Expression.SchemaName,
- ForeignTable = foreignTableName,
- ForeignTableSchema = foreignTableSchema
- }
- };
+ var fk = new CreateForeignKeyExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax, new ForeignKeyDefinition
+ {
+ Name = foreignKeyName,
+ PrimaryTable = Expression.TableName,
+ PrimaryTableSchema = Expression.SchemaName,
+ ForeignTable = foreignTableName,
+ ForeignTableSchema = foreignTableSchema
+ });
fk.ForeignKey.PrimaryColumns.Add(CurrentColumn.Name);
fk.ForeignKey.ForeignColumns.Add(foreignColumnName);
@@ -220,7 +211,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table
public IAlterTableColumnTypeSyntax AddColumn(string name)
{
var column = new ColumnDefinition { Name = name, ModificationType = ModificationType.Create };
- var createColumn = new CreateColumnExpression
+ var createColumn = new CreateColumnExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax)
{
Column = column,
SchemaName = Expression.SchemaName,
@@ -236,12 +227,12 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table
public IAlterTableColumnTypeSyntax AlterColumn(string name)
{
var column = new ColumnDefinition { Name = name, ModificationType = ModificationType.Alter };
- var alterColumn = new AlterColumnExpression
- {
- Column = column,
- SchemaName = Expression.SchemaName,
- TableName = Expression.TableName
- };
+ var alterColumn = new AlterColumnExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax)
+ {
+ Column = column,
+ SchemaName = Expression.SchemaName,
+ TableName = Expression.TableName
+ };
CurrentColumn = column;
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Column/CreateColumnBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Column/CreateColumnBuilder.cs
index 439733bc46..d004cd1176 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Column/CreateColumnBuilder.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Column/CreateColumnBuilder.cs
@@ -1,6 +1,7 @@
using System.Data;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Migrations.Syntax.Expressions;
+using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Column
{
@@ -10,11 +11,13 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Column
ICreateColumnOptionForeignKeyCascadeSyntax
{
private readonly IMigrationContext _context;
+ private readonly DatabaseProviders[] _databaseProviders;
- public CreateColumnBuilder(CreateColumnExpression expression, IMigrationContext context)
+ public CreateColumnBuilder(IMigrationContext context, DatabaseProviders[] databaseProviders, CreateColumnExpression expression)
: base(expression)
{
_context = context;
+ _databaseProviders = databaseProviders;
}
public ForeignKeyDefinition CurrentForeignKey { get; set; }
@@ -56,15 +59,12 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Column
{
Expression.Column.IsIndexed = true;
- var index = new CreateIndexExpression
- {
- Index = new IndexDefinition
- {
- Name = indexName,
- SchemaName = Expression.SchemaName,
- TableName = Expression.TableName
- }
- };
+ var index = new CreateIndexExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax, new IndexDefinition
+ {
+ Name = indexName,
+ SchemaName = Expression.SchemaName,
+ TableName = Expression.TableName
+ });
index.Index.Columns.Add(new IndexColumnDefinition
{
@@ -110,16 +110,13 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Column
{
Expression.Column.IsUnique = true;
- var index = new CreateIndexExpression
- {
- Index = new IndexDefinition
- {
- Name = indexName,
- SchemaName = Expression.SchemaName,
- TableName = Expression.TableName,
- IsUnique = true
- }
- };
+ var index = new CreateIndexExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax, new IndexDefinition
+ {
+ Name = indexName,
+ SchemaName = Expression.SchemaName,
+ TableName = Expression.TableName,
+ IsUnique = true
+ });
index.Index.Columns.Add(new IndexColumnDefinition
{
@@ -147,17 +144,14 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Column
{
Expression.Column.IsForeignKey = true;
- var fk = new CreateForeignKeyExpression
- {
- ForeignKey = new ForeignKeyDefinition
- {
- Name = foreignKeyName,
- PrimaryTable = primaryTableName,
- PrimaryTableSchema = primaryTableSchema,
- ForeignTable = Expression.TableName,
- ForeignTableSchema = Expression.SchemaName
- }
- };
+ var fk = new CreateForeignKeyExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax, new ForeignKeyDefinition
+ {
+ Name = foreignKeyName,
+ PrimaryTable = primaryTableName,
+ PrimaryTableSchema = primaryTableSchema,
+ ForeignTable = Expression.TableName,
+ ForeignTableSchema = Expression.SchemaName
+ });
fk.ForeignKey.PrimaryColumns.Add(primaryColumnName);
fk.ForeignKey.ForeignColumns.Add(Expression.Column.Name);
@@ -187,17 +181,14 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Column
public ICreateColumnOptionForeignKeyCascadeSyntax ReferencedBy(string foreignKeyName, string foreignTableSchema,
string foreignTableName, string foreignColumnName)
{
- var fk = new CreateForeignKeyExpression
- {
- ForeignKey = new ForeignKeyDefinition
- {
- Name = foreignKeyName,
- PrimaryTable = Expression.TableName,
- PrimaryTableSchema = Expression.SchemaName,
- ForeignTable = foreignTableName,
- ForeignTableSchema = foreignTableSchema
- }
- };
+ var fk = new CreateForeignKeyExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax, new ForeignKeyDefinition
+ {
+ Name = foreignKeyName,
+ PrimaryTable = Expression.TableName,
+ PrimaryTableSchema = Expression.SchemaName,
+ ForeignTable = foreignTableName,
+ ForeignTableSchema = foreignTableSchema
+ });
fk.ForeignKey.PrimaryColumns.Add(Expression.Column.Name);
fk.ForeignKey.ForeignColumns.Add(foreignColumnName);
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/CreateBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/CreateBuilder.cs
index 4f2666d032..e3ad6f972d 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/CreateBuilder.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/CreateBuilder.cs
@@ -19,75 +19,66 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create
public CreateBuilder(IMigrationContext context, ISqlSyntaxProvider sqlSyntax, params DatabaseProviders[] databaseProviders)
{
+ if (context == null) throw new ArgumentNullException("context");
+ if (sqlSyntax == null) throw new ArgumentNullException("sqlSyntax");
+
_context = context;
_sqlSyntax = sqlSyntax;
_databaseProviders = databaseProviders;
}
- [Obsolete("Use alternate ctor specifying ISqlSyntaxProvider instead")]
- public CreateBuilder(IMigrationContext context, params DatabaseProviders[] databaseProviders)
- :this(context, SqlSyntaxContext.SqlSyntaxProvider, databaseProviders)
- {
- }
-
public ICreateTableWithColumnSyntax Table(string tableName)
{
- var expression = new CreateTableExpression { TableName = tableName };
+ var expression = new CreateTableExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax) { TableName = tableName };
_context.Expressions.Add(expression);
- return new CreateTableBuilder(expression, _context);
+ return new CreateTableBuilder(_context, _databaseProviders, expression);
}
public ICreateColumnOnTableSyntax Column(string columnName)
{
- var expression = _databaseProviders == null
- ? new CreateColumnExpression { Column = { Name = columnName } }
- : new CreateColumnExpression(_context.CurrentDatabaseProvider, _databaseProviders) { Column = { Name = columnName } };
+ var expression = new CreateColumnExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax) { Column = { Name = columnName } };
_context.Expressions.Add(expression);
- return new CreateColumnBuilder(expression, _context);
+ return new CreateColumnBuilder(_context, _databaseProviders, expression);
}
public ICreateForeignKeyFromTableSyntax ForeignKey()
{
- var expression = _databaseProviders == null
- ? new CreateForeignKeyExpression()
- : new CreateForeignKeyExpression(_context.CurrentDatabaseProvider, _databaseProviders);
+ var expression = new CreateForeignKeyExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax);
_context.Expressions.Add(expression);
return new CreateForeignKeyBuilder(expression);
}
public ICreateForeignKeyFromTableSyntax ForeignKey(string foreignKeyName)
{
- var expression = _databaseProviders == null
- ? new CreateForeignKeyExpression { ForeignKey = { Name = foreignKeyName } }
- : new CreateForeignKeyExpression(_context.CurrentDatabaseProvider, _databaseProviders) { ForeignKey = { Name = foreignKeyName } };
+ var expression = new CreateForeignKeyExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax) { ForeignKey = { Name = foreignKeyName } };
_context.Expressions.Add(expression);
return new CreateForeignKeyBuilder(expression);
}
public ICreateIndexForTableSyntax Index()
{
- var expression = new CreateIndexExpression(_sqlSyntax);
+ var expression = new CreateIndexExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax);
_context.Expressions.Add(expression);
return new CreateIndexBuilder(expression);
}
public ICreateIndexForTableSyntax Index(string indexName)
{
- var expression = new CreateIndexExpression(_sqlSyntax) { Index = { Name = indexName } };
+ var expression = new CreateIndexExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax) { Index = { Name = indexName } };
_context.Expressions.Add(expression);
return new CreateIndexBuilder(expression);
}
public ICreateConstraintOnTableSyntax PrimaryKey()
{
- var expression = new CreateConstraintExpression(ConstraintType.PrimaryKey);
+ var expression = new CreateConstraintExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax, ConstraintType.PrimaryKey);
_context.Expressions.Add(expression);
return new CreateConstraintBuilder(expression);
}
public ICreateConstraintOnTableSyntax PrimaryKey(string primaryKeyName)
{
- var expression = new CreateConstraintExpression(ConstraintType.PrimaryKey);
+ var expression = new CreateConstraintExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax, ConstraintType.PrimaryKey);
expression.Constraint.ConstraintName = primaryKeyName;
_context.Expressions.Add(expression);
return new CreateConstraintBuilder(expression);
@@ -95,14 +86,14 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create
public ICreateConstraintOnTableSyntax UniqueConstraint()
{
- var expression = new CreateConstraintExpression(ConstraintType.Unique);
+ var expression = new CreateConstraintExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax, ConstraintType.Unique);
_context.Expressions.Add(expression);
return new CreateConstraintBuilder(expression);
}
public ICreateConstraintOnTableSyntax UniqueConstraint(string constraintName)
{
- var expression = new CreateConstraintExpression(ConstraintType.Unique);
+ var expression = new CreateConstraintExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax, ConstraintType.Unique);
expression.Constraint.ConstraintName = constraintName;
_context.Expressions.Add(expression);
return new CreateConstraintBuilder(expression);
@@ -110,7 +101,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create
public ICreateConstraintOnTableSyntax Constraint(string constraintName)
{
- var expression = new CreateConstraintExpression(ConstraintType.NonUnique);
+ var expression = new CreateConstraintExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax, ConstraintType.NonUnique);
expression.Constraint.ConstraintName = constraintName;
_context.Expressions.Add(expression);
return new CreateConstraintBuilder(expression);
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Expressions/CreateConstraintExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Expressions/CreateConstraintExpression.cs
index b575a89c49..a06775929b 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Expressions/CreateConstraintExpression.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Expressions/CreateConstraintExpression.cs
@@ -6,10 +6,12 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Expressions
{
public class CreateConstraintExpression : MigrationExpressionBase
{
- public CreateConstraintExpression(ConstraintType type)
+ public CreateConstraintExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax, ConstraintType constraint)
+ : base(current, databaseProviders, sqlSyntax)
{
- Constraint = new ConstraintDefinition(type);
+ Constraint = new ConstraintDefinition(constraint);
}
+
public ConstraintDefinition Constraint { get; private set; }
@@ -17,7 +19,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Expressions
{
var constraintType = (Constraint.IsPrimaryKeyConstraint) ? "PRIMARY KEY" : "UNIQUE";
- if (Constraint.IsPrimaryKeyConstraint && SqlSyntaxContext.SqlSyntaxProvider.SupportsClustered())
+ if (Constraint.IsPrimaryKeyConstraint && SqlSyntax.SupportsClustered())
constraintType += " CLUSTERED";
if (Constraint.IsNonUniqueConstraint)
@@ -27,12 +29,12 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Expressions
for (int i = 0; i < Constraint.Columns.Count; i++)
{
- columns[i] = SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(Constraint.Columns.ElementAt(i));
+ columns[i] = SqlSyntax.GetQuotedColumnName(Constraint.Columns.ElementAt(i));
}
- return string.Format(SqlSyntaxContext.SqlSyntaxProvider.CreateConstraint,
- SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(Constraint.TableName),
- SqlSyntaxContext.SqlSyntaxProvider.GetQuotedName(Constraint.ConstraintName),
+ return string.Format(SqlSyntax.CreateConstraint,
+ SqlSyntax.GetQuotedTableName(Constraint.TableName),
+ SqlSyntax.GetQuotedName(Constraint.ConstraintName),
constraintType,
string.Join(", ", columns));
}
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Expressions/CreateTableExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Expressions/CreateTableExpression.cs
index c048bda198..8cf37e74d2 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Expressions/CreateTableExpression.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Expressions/CreateTableExpression.cs
@@ -7,24 +7,24 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Expressions
{
public class CreateTableExpression : MigrationExpressionBase
{
- [Obsolete("Use the other constructors specifying an ISqlSyntaxProvider instead")]
- public CreateTableExpression()
- {
- Columns = new List();
- }
+ //[Obsolete("Use the other constructors specifying an ISqlSyntaxProvider instead")]
+ //public CreateTableExpression()
+ //{
+ // Columns = new List();
+ //}
- [Obsolete("Use the other constructors specifying an ISqlSyntaxProvider instead")]
- public CreateTableExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders)
- : base(current, databaseProviders)
- {
- Columns = new List();
- }
+ //[Obsolete("Use the other constructors specifying an ISqlSyntaxProvider instead")]
+ //public CreateTableExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders)
+ // : base(current, databaseProviders)
+ //{
+ // Columns = new List();
+ //}
- public CreateTableExpression(ISqlSyntaxProvider sqlSyntax)
- : base(sqlSyntax)
- {
- Columns = new List();
- }
+ //public CreateTableExpression(ISqlSyntaxProvider sqlSyntax)
+ // : base(sqlSyntax)
+ //{
+ // Columns = new List();
+ //}
public CreateTableExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
: base(current, databaseProviders, sqlSyntax)
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Table/CreateTableBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Table/CreateTableBuilder.cs
index 58eef672eb..86760b71bc 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Table/CreateTableBuilder.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Table/CreateTableBuilder.cs
@@ -2,6 +2,7 @@
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Migrations.Syntax.Create.Expressions;
using Umbraco.Core.Persistence.Migrations.Syntax.Expressions;
+using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Table
{
@@ -11,11 +12,13 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Table
ICreateTableColumnOptionForeignKeyCascadeSyntax
{
private readonly IMigrationContext _context;
+ private readonly DatabaseProviders[] _databaseProviders;
- public CreateTableBuilder(CreateTableExpression expression, IMigrationContext context)
+ public CreateTableBuilder(IMigrationContext context, DatabaseProviders[] databaseProviders, CreateTableExpression expression)
: base(expression)
{
_context = context;
+ _databaseProviders = databaseProviders;
}
public ColumnDefinition CurrentColumn { get; set; }
@@ -62,15 +65,12 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Table
{
CurrentColumn.IsIndexed = true;
- var index = new CreateIndexExpression
- {
- Index = new IndexDefinition
- {
- Name = indexName,
- SchemaName = Expression.SchemaName,
- TableName = Expression.TableName
- }
- };
+ var index = new CreateIndexExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax, new IndexDefinition
+ {
+ Name = indexName,
+ SchemaName = Expression.SchemaName,
+ TableName = Expression.TableName
+ });
index.Index.Columns.Add(new IndexColumnDefinition
{
@@ -86,15 +86,25 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Table
{
CurrentColumn.IsPrimaryKey = true;
- var expression = new CreateConstraintExpression(ConstraintType.PrimaryKey)
+ //For MySQL, the PK will be created WITH the create table expression, however for
+ // SQL Server, the PK get's created in a different Alter table expression afterwords.
+ // MySQL will choke if the same constraint is again added afterword
+ // TODO: This is a super hack, I'd rather not add another property like 'CreatesPkInCreateTableDefinition' to check
+ // for this, but I don't see another way around. MySQL doesn't support checking for a constraint before creating
+ // it... except in a very strange way but it doesn't actually provider error feedback if it doesn't work so we cannot use
+ // it. For now, this is what I'm doing
+ if (Expression.CurrentDatabaseProvider != DatabaseProviders.MySql)
{
- Constraint =
+ var expression = new CreateConstraintExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax, ConstraintType.PrimaryKey)
+ {
+ Constraint =
{
TableName = CurrentColumn.TableName,
Columns = new[] { CurrentColumn.Name }
}
- };
- _context.Expressions.Add(expression);
+ };
+ _context.Expressions.Add(expression);
+ }
return this;
}
@@ -104,16 +114,27 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Table
CurrentColumn.IsPrimaryKey = true;
CurrentColumn.PrimaryKeyName = primaryKeyName;
- var expression = new CreateConstraintExpression(ConstraintType.PrimaryKey)
+ //For MySQL, the PK will be created WITH the create table expression, however for
+ // SQL Server, the PK get's created in a different Alter table expression afterwords.
+ // MySQL will choke if the same constraint is again added afterword
+ // TODO: This is a super hack, I'd rather not add another property like 'CreatesPkInCreateTableDefinition' to check
+ // for this, but I don't see another way around. MySQL doesn't support checking for a constraint before creating
+ // it... except in a very strange way but it doesn't actually provider error feedback if it doesn't work so we cannot use
+ // it. For now, this is what I'm doing
+
+ if (Expression.CurrentDatabaseProvider != DatabaseProviders.MySql)
{
- Constraint =
+ var expression = new CreateConstraintExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax, ConstraintType.PrimaryKey)
+ {
+ Constraint =
{
ConstraintName = primaryKeyName,
TableName = CurrentColumn.TableName,
Columns = new[] { CurrentColumn.Name }
}
- };
- _context.Expressions.Add(expression);
+ };
+ _context.Expressions.Add(expression);
+ }
return this;
}
@@ -139,16 +160,13 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Table
{
CurrentColumn.IsUnique = true;
- var index = new CreateIndexExpression
- {
- Index = new IndexDefinition
- {
- Name = indexName,
- SchemaName = Expression.SchemaName,
- TableName = Expression.TableName,
- IsUnique = true
- }
- };
+ var index = new CreateIndexExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax, new IndexDefinition
+ {
+ Name = indexName,
+ SchemaName = Expression.SchemaName,
+ TableName = Expression.TableName,
+ IsUnique = true
+ });
index.Index.Columns.Add(new IndexColumnDefinition
{
@@ -176,17 +194,14 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Table
{
CurrentColumn.IsForeignKey = true;
- var fk = new CreateForeignKeyExpression
- {
- ForeignKey = new ForeignKeyDefinition
- {
- Name = foreignKeyName,
- PrimaryTable = primaryTableName,
- PrimaryTableSchema = primaryTableSchema,
- ForeignTable = Expression.TableName,
- ForeignTableSchema = Expression.SchemaName
- }
- };
+ var fk = new CreateForeignKeyExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax, new ForeignKeyDefinition
+ {
+ Name = foreignKeyName,
+ PrimaryTable = primaryTableName,
+ PrimaryTableSchema = primaryTableSchema,
+ ForeignTable = Expression.TableName,
+ ForeignTableSchema = Expression.SchemaName
+ });
fk.ForeignKey.PrimaryColumns.Add(primaryColumnName);
fk.ForeignKey.ForeignColumns.Add(CurrentColumn.Name);
@@ -216,17 +231,14 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Table
public ICreateTableColumnOptionForeignKeyCascadeSyntax ReferencedBy(string foreignKeyName, string foreignTableSchema,
string foreignTableName, string foreignColumnName)
{
- var fk = new CreateForeignKeyExpression
- {
- ForeignKey = new ForeignKeyDefinition
- {
- Name = foreignKeyName,
- PrimaryTable = Expression.TableName,
- PrimaryTableSchema = Expression.SchemaName,
- ForeignTable = foreignTableName,
- ForeignTableSchema = foreignTableSchema
- }
- };
+ var fk = new CreateForeignKeyExpression(_context.CurrentDatabaseProvider, _databaseProviders, Expression.SqlSyntax, new ForeignKeyDefinition
+ {
+ Name = foreignKeyName,
+ PrimaryTable = Expression.TableName,
+ PrimaryTableSchema = Expression.SchemaName,
+ ForeignTable = foreignTableName,
+ ForeignTableSchema = foreignTableSchema
+ });
fk.ForeignKey.PrimaryColumns.Add(CurrentColumn.Name);
fk.ForeignKey.ForeignColumns.Add(foreignColumnName);
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/DeleteBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/DeleteBuilder.cs
index f70de5b548..18ea700ed2 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/DeleteBuilder.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/DeleteBuilder.cs
@@ -23,69 +23,57 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete
_databaseProviders = databaseProviders;
}
- [Obsolete("Use the other constructor specifying an ISqlSyntaxProvider instead")]
- public DeleteBuilder(IMigrationContext context, params DatabaseProviders[] databaseProviders)
- : this(context, SqlSyntaxContext.SqlSyntaxProvider, databaseProviders)
- {
- }
-
public void Table(string tableName)
{
- var expression = new DeleteTableExpression { TableName = tableName };
+ var expression = new DeleteTableExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax) { TableName = tableName };
_context.Expressions.Add(expression);
}
public IDeleteColumnFromTableSyntax Column(string columnName)
{
- var expression = _databaseProviders == null
- ? new DeleteColumnExpression { ColumnNames = { columnName } }
- : new DeleteColumnExpression(_context.CurrentDatabaseProvider, _databaseProviders) { ColumnNames = { columnName } };
+ var expression = new DeleteColumnExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax) {ColumnNames = {columnName}};
_context.Expressions.Add(expression);
return new DeleteColumnBuilder(expression);
}
public IDeleteForeignKeyFromTableSyntax ForeignKey()
{
- var expression = _databaseProviders == null
- ? new DeleteForeignKeyExpression(_sqlSyntax)
- : new DeleteForeignKeyExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax);
+ var expression = new DeleteForeignKeyExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax);
_context.Expressions.Add(expression);
return new DeleteForeignKeyBuilder(expression);
}
public IDeleteForeignKeyOnTableSyntax ForeignKey(string foreignKeyName)
{
- var expression = _databaseProviders == null
- ? new DeleteForeignKeyExpression(_sqlSyntax) { ForeignKey = { Name = foreignKeyName } }
- : new DeleteForeignKeyExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax) { ForeignKey = { Name = foreignKeyName } };
+ var expression = new DeleteForeignKeyExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax) {ForeignKey = {Name = foreignKeyName}};
_context.Expressions.Add(expression);
return new DeleteForeignKeyBuilder(expression);
}
public IDeleteDataSyntax FromTable(string tableName)
{
- var expression = new DeleteDataExpression { TableName = tableName };
+ var expression = new DeleteDataExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax) { TableName = tableName };
_context.Expressions.Add(expression);
return new DeleteDataBuilder(expression);
}
public IDeleteIndexForTableSyntax Index()
{
- var expression = new DeleteIndexExpression();
+ var expression = new DeleteIndexExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax);
_context.Expressions.Add(expression);
return new DeleteIndexBuilder(expression);
}
public IDeleteIndexForTableSyntax Index(string indexName)
{
- var expression = new DeleteIndexExpression { Index = { Name = indexName } };
+ var expression = new DeleteIndexExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax) { Index = { Name = indexName } };
_context.Expressions.Add(expression);
return new DeleteIndexBuilder(expression);
}
public IDeleteConstraintOnTableSyntax PrimaryKey(string primaryKeyName)
{
- var expression = new DeleteConstraintExpression(_context.CurrentDatabaseProvider, _databaseProviders, ConstraintType.PrimaryKey)
+ var expression = new DeleteConstraintExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax, ConstraintType.PrimaryKey)
{
Constraint = { ConstraintName = primaryKeyName }
};
@@ -95,7 +83,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete
public IDeleteConstraintOnTableSyntax UniqueConstraint(string constraintName)
{
- var expression = new DeleteConstraintExpression(ConstraintType.Unique)
+ var expression = new DeleteConstraintExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax, ConstraintType.Unique)
{
Constraint = { ConstraintName = constraintName }
};
@@ -105,9 +93,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete
public IDeleteDefaultConstraintOnTableSyntax DefaultConstraint()
{
- var expression = _databaseProviders == null
- ? new DeleteDefaultConstraintExpression()
- : new DeleteDefaultConstraintExpression(_context.CurrentDatabaseProvider, _databaseProviders);
+ var expression = new DeleteDefaultConstraintExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax);
_context.Expressions.Add(expression);
return new DeleteDefaultConstraintBuilder(expression);
}
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteColumnExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteColumnExpression.cs
index c9f8c8d04d..b02bca6f12 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteColumnExpression.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteColumnExpression.cs
@@ -7,13 +7,13 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
{
public class DeleteColumnExpression : MigrationExpressionBase
{
- public DeleteColumnExpression()
- {
- ColumnNames = new List();
- }
+ //public DeleteColumnExpression()
+ //{
+ // ColumnNames = new List();
+ //}
- public DeleteColumnExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders)
- : base(current, databaseProviders)
+ public DeleteColumnExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
+ : base(current, databaseProviders, sqlSyntax)
{
ColumnNames = new List();
}
@@ -31,9 +31,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
foreach (string columnName in ColumnNames)
{
if (ColumnNames.First() != columnName) sb.AppendLine(";");
- sb.AppendFormat(SqlSyntaxContext.SqlSyntaxProvider.DropColumn,
- SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName),
- SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(columnName));
+ sb.AppendFormat(SqlSyntax.DropColumn,
+ SqlSyntax.GetQuotedTableName(TableName),
+ SqlSyntax.GetQuotedColumnName(columnName));
}
return sb.ToString();
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteConstraintExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteConstraintExpression.cs
index 39f250532d..21ef6bb517 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteConstraintExpression.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteConstraintExpression.cs
@@ -5,13 +5,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
{
public class DeleteConstraintExpression : MigrationExpressionBase
{
- public DeleteConstraintExpression(ConstraintType type)
- {
- Constraint = new ConstraintDefinition(type);
- }
-
- public DeleteConstraintExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ConstraintType type)
- : base(current, databaseProviders)
+
+ public DeleteConstraintExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax, ConstraintType type)
+ : base(current, databaseProviders, sqlSyntax)
{
Constraint = new ConstraintDefinition(type);
}
@@ -25,24 +21,24 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
{
if (Constraint.IsPrimaryKeyConstraint)
{
- return string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteConstraint,
- SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(Constraint.TableName),
+ return string.Format(SqlSyntax.DeleteConstraint,
+ SqlSyntax.GetQuotedTableName(Constraint.TableName),
"PRIMARY KEY",
"");
}
else
{
- return string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteConstraint,
- SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(Constraint.TableName),
+ return string.Format(SqlSyntax.DeleteConstraint,
+ SqlSyntax.GetQuotedTableName(Constraint.TableName),
"FOREIGN KEY",
"");
}
}
else
{
- return string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteConstraint,
- SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(Constraint.TableName),
- SqlSyntaxContext.SqlSyntaxProvider.GetQuotedName(Constraint.ConstraintName));
+ return string.Format(SqlSyntax.DeleteConstraint,
+ SqlSyntax.GetQuotedTableName(Constraint.TableName),
+ SqlSyntax.GetQuotedName(Constraint.ConstraintName));
}
}
}
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteDataExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteDataExpression.cs
index 73966f6e93..97c601a2a1 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteDataExpression.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteDataExpression.cs
@@ -8,12 +8,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
public class DeleteDataExpression : MigrationExpressionBase
{
private readonly List _rows = new List();
-
- public DeleteDataExpression()
- {
- }
-
- public DeleteDataExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders) : base(current, databaseProviders)
+
+ public DeleteDataExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
+ : base(current, databaseProviders, sqlSyntax)
{
}
@@ -32,7 +29,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
if (IsAllRows)
{
- deleteItems.Add(string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteData, SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName), "1 = 1"));
+ deleteItems.Add(string.Format(SqlSyntax.DeleteData, SqlSyntax.GetQuotedTableName(TableName), "1 = 1"));
}
else
{
@@ -42,13 +39,13 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
foreach (KeyValuePair item in row)
{
whereClauses.Add(string.Format("{0} {1} {2}",
- SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(item.Key),
+ SqlSyntax.GetQuotedColumnName(item.Key),
item.Value == null ? "IS" : "=",
GetQuotedValue(item.Value)));
}
- deleteItems.Add(string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteData,
- SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName),
+ deleteItems.Add(string.Format(SqlSyntax.DeleteData,
+ SqlSyntax.GetQuotedTableName(TableName),
String.Join(" AND ", whereClauses.ToArray())));
}
}
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteDefaultConstraintExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteDefaultConstraintExpression.cs
index 43677d23e3..70a74da28e 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteDefaultConstraintExpression.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteDefaultConstraintExpression.cs
@@ -4,12 +4,8 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
{
public class DeleteDefaultConstraintExpression : MigrationExpressionBase
{
- public DeleteDefaultConstraintExpression()
- {
- }
-
- public DeleteDefaultConstraintExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders)
- : base(current, databaseProviders)
+ public DeleteDefaultConstraintExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
+ : base(current, databaseProviders, sqlSyntax)
{
}
@@ -22,7 +18,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
if (IsExpressionSupported() == false)
return string.Empty;
- return string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteDefaultConstraint,
+ return string.Format(SqlSyntax.DeleteDefaultConstraint,
TableName,
ColumnName);
}
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteForeignKeyExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteForeignKeyExpression.cs
index 34e3bd65c5..e0fef06f3f 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteForeignKeyExpression.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteForeignKeyExpression.cs
@@ -8,24 +8,11 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
{
public class DeleteForeignKeyExpression : MigrationExpressionBase
{
- [Obsolete("Use the other constructors specifying an ILogger instead")]
- public DeleteForeignKeyExpression()
- {
- ForeignKey = new ForeignKeyDefinition();
- }
-
- [Obsolete("Use the other constructors specifying an ILogger instead")]
- public DeleteForeignKeyExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders)
- : base(current, databaseProviders)
- {
- ForeignKey = new ForeignKeyDefinition();
- }
-
- public DeleteForeignKeyExpression(ISqlSyntaxProvider sqlSyntax)
- : base(sqlSyntax)
- {
- ForeignKey = new ForeignKeyDefinition();
- }
+ //public DeleteForeignKeyExpression(ISqlSyntaxProvider sqlSyntax)
+ // : base(sqlSyntax)
+ //{
+ // ForeignKey = new ForeignKeyDefinition();
+ //}
public DeleteForeignKeyExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
: base(current, databaseProviders, sqlSyntax)
@@ -33,7 +20,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
ForeignKey = new ForeignKeyDefinition();
}
- public virtual ForeignKeyDefinition ForeignKey { get; set; }
+ public ForeignKeyDefinition ForeignKey { get; set; }
public override string ToString()
{
@@ -45,7 +32,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
if (CurrentDatabaseProvider == DatabaseProviders.MySql)
{
- //MySql naming "convention" for foreignkeys, which aren't explicitly named
+ //MySql naming "convention" for foreignkeys, which aren't explicitly named
if (string.IsNullOrEmpty(ForeignKey.Name))
ForeignKey.Name = string.Format("{0}_ibfk_1", ForeignKey.ForeignTable.ToLower());
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteIndexExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteIndexExpression.cs
index 3e1a959925..e504223669 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteIndexExpression.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteIndexExpression.cs
@@ -5,23 +5,26 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
{
public class DeleteIndexExpression : MigrationExpressionBase
{
- public DeleteIndexExpression()
+
+ public DeleteIndexExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
+ : base(current, databaseProviders, sqlSyntax)
{
Index = new IndexDefinition();
}
- public DeleteIndexExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders) : base(current, databaseProviders)
+ public DeleteIndexExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax, IndexDefinition index)
+ : base(current, databaseProviders, sqlSyntax)
{
- Index = new IndexDefinition();
+ Index = index;
}
- public virtual IndexDefinition Index { get; set; }
+ public IndexDefinition Index { get; private set; }
public override string ToString()
{
- return string.Format(SqlSyntaxContext.SqlSyntaxProvider.DropIndex,
- SqlSyntaxContext.SqlSyntaxProvider.GetQuotedName(Index.Name),
- SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(Index.TableName));
+ return string.Format(SqlSyntax.DropIndex,
+ SqlSyntax.GetQuotedName(Index.Name),
+ SqlSyntax.GetQuotedTableName(Index.TableName));
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteTableExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteTableExpression.cs
index 2fff4e75e0..0456091a4b 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteTableExpression.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteTableExpression.cs
@@ -4,11 +4,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
{
public class DeleteTableExpression : MigrationExpressionBase
{
- public DeleteTableExpression()
- {
- }
-
- public DeleteTableExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders) : base(current, databaseProviders)
+
+ public DeleteTableExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
+ : base(current, databaseProviders, sqlSyntax)
{
}
@@ -17,8 +15,8 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
public override string ToString()
{
- return string.Format(SqlSyntaxContext.SqlSyntaxProvider.DropTable,
- SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName));
+ return string.Format(SqlSyntax.DropTable,
+ SqlSyntax.GetQuotedTableName(TableName));
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/IDeleteBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/IDeleteBuilder.cs
index 6521d043a7..4a31c3bf37 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/IDeleteBuilder.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/IDeleteBuilder.cs
@@ -12,7 +12,6 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete
void Table(string tableName);
IDeleteColumnFromTableSyntax Column(string columnName);
IDeleteForeignKeyFromTableSyntax ForeignKey();
- [Obsolete("Do not use this construct as it does not work with MySql, use the syntax: Delete.ForeignKey().FromTable(\"umbracoUser2app\").ForeignColumn(... instead")]
IDeleteForeignKeyOnTableSyntax ForeignKey(string foreignKeyName);
IDeleteDataSyntax FromTable(string tableName);
IDeleteIndexForTableSyntax Index();
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Execute/ExecuteBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Execute/ExecuteBuilder.cs
index e537253664..549a4a0c66 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Execute/ExecuteBuilder.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Execute/ExecuteBuilder.cs
@@ -1,34 +1,31 @@
using System;
using Umbraco.Core.Persistence.Migrations.Syntax.Execute.Expressions;
+using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Syntax.Execute
{
public class ExecuteBuilder : IExecuteBuilder
{
private readonly IMigrationContext _context;
+ private readonly ISqlSyntaxProvider _sqlSyntax;
private readonly DatabaseProviders[] _databaseProviders;
- public ExecuteBuilder(IMigrationContext context, params DatabaseProviders[] databaseProviders)
+ public ExecuteBuilder(IMigrationContext context, ISqlSyntaxProvider sqlSyntax, params DatabaseProviders[] databaseProviders)
{
_context = context;
+ _sqlSyntax = sqlSyntax;
_databaseProviders = databaseProviders;
}
public void Sql(string sqlStatement)
{
- var expression = _databaseProviders == null
- ? new ExecuteSqlStatementExpression {SqlStatement = sqlStatement}
- : new ExecuteSqlStatementExpression(_context.CurrentDatabaseProvider,
- _databaseProviders) {SqlStatement = sqlStatement};
+ var expression = new ExecuteSqlStatementExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax) {SqlStatement = sqlStatement};
_context.Expressions.Add(expression);
}
public void Code(Func codeStatement)
{
- var expression = _databaseProviders == null
- ? new ExecuteCodeStatementExpression { CodeStatement = codeStatement }
- : new ExecuteCodeStatementExpression(_context.CurrentDatabaseProvider,
- _databaseProviders) { CodeStatement = codeStatement };
+ var expression = new ExecuteCodeStatementExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax) { CodeStatement = codeStatement };
_context.Expressions.Add(expression);
}
}
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Execute/Expressions/ExecuteCodeStatementExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Execute/Expressions/ExecuteCodeStatementExpression.cs
index 0f88fe2ee6..e5f487d15d 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Execute/Expressions/ExecuteCodeStatementExpression.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Execute/Expressions/ExecuteCodeStatementExpression.cs
@@ -1,15 +1,12 @@
using System;
+using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Syntax.Execute.Expressions
{
public class ExecuteCodeStatementExpression : MigrationExpressionBase
{
- public ExecuteCodeStatementExpression()
- {
- }
-
- public ExecuteCodeStatementExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders)
- : base(current, databaseProviders)
+ public ExecuteCodeStatementExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
+ : base(current, databaseProviders, sqlSyntax)
{
}
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Execute/Expressions/ExecuteSqlStatementExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Execute/Expressions/ExecuteSqlStatementExpression.cs
index 308a7719dd..1164ba7caa 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Execute/Expressions/ExecuteSqlStatementExpression.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Execute/Expressions/ExecuteSqlStatementExpression.cs
@@ -1,12 +1,12 @@
-namespace Umbraco.Core.Persistence.Migrations.Syntax.Execute.Expressions
+using Umbraco.Core.Persistence.SqlSyntax;
+
+namespace Umbraco.Core.Persistence.Migrations.Syntax.Execute.Expressions
{
public class ExecuteSqlStatementExpression : MigrationExpressionBase
{
- public ExecuteSqlStatementExpression()
- {
- }
- public ExecuteSqlStatementExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders) : base(current, databaseProviders)
+ public ExecuteSqlStatementExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
+ : base(current, databaseProviders, sqlSyntax)
{
}
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateColumnExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateColumnExpression.cs
index 5c7bf3c0b7..ad16da5286 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateColumnExpression.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateColumnExpression.cs
@@ -5,20 +5,16 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Expressions
{
public class CreateColumnExpression : MigrationExpressionBase
{
- public CreateColumnExpression()
+
+ public CreateColumnExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
+ : base(current, databaseProviders, sqlSyntax)
{
Column = new ColumnDefinition { ModificationType = ModificationType.Create };
}
- public CreateColumnExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders)
- : base(current, databaseProviders)
- {
- Column = new ColumnDefinition { ModificationType = ModificationType.Create };
- }
-
- public virtual string SchemaName { get; set; }
- public virtual string TableName { get; set; }
- public virtual ColumnDefinition Column { get; set; }
+ public string SchemaName { get; set; }
+ public string TableName { get; set; }
+ public ColumnDefinition Column { get; set; }
public override string ToString()
{
@@ -28,9 +24,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Expressions
if (string.IsNullOrEmpty(Column.TableName))
Column.TableName = TableName;
- return string.Format(SqlSyntaxContext.SqlSyntaxProvider.AddColumn,
- SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(Column.TableName),
- SqlSyntaxContext.SqlSyntaxProvider.Format(Column));
+ return string.Format(SqlSyntax.AddColumn,
+ SqlSyntax.GetQuotedTableName(Column.TableName),
+ SqlSyntax.Format(Column));
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateForeignKeyExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateForeignKeyExpression.cs
index c6c0c437ef..45e40e961f 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateForeignKeyExpression.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateForeignKeyExpression.cs
@@ -5,25 +5,26 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Expressions
{
public class CreateForeignKeyExpression : MigrationExpressionBase
{
- public CreateForeignKeyExpression()
+ public CreateForeignKeyExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax, ForeignKeyDefinition fkDef)
+ : base(current, databaseProviders, sqlSyntax)
+ {
+ ForeignKey = fkDef;
+ }
+
+ public CreateForeignKeyExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
+ : base(current, databaseProviders, sqlSyntax)
{
ForeignKey = new ForeignKeyDefinition();
}
- public CreateForeignKeyExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders)
- : base(current, databaseProviders)
- {
- ForeignKey = new ForeignKeyDefinition();
- }
-
- public virtual ForeignKeyDefinition ForeignKey { get; set; }
+ public ForeignKeyDefinition ForeignKey { get; set; }
public override string ToString()
{
if (IsExpressionSupported() == false)
return string.Empty;
- return SqlSyntaxContext.SqlSyntaxProvider.Format(ForeignKey);
+ return SqlSyntax.Format(ForeignKey);
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateIndexExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateIndexExpression.cs
index eadb30cd9e..7fa38cd3ae 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateIndexExpression.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateIndexExpression.cs
@@ -6,32 +6,20 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Expressions
{
public class CreateIndexExpression : MigrationExpressionBase
{
- public CreateIndexExpression(ISqlSyntaxProvider sqlSyntax)
- : base(sqlSyntax)
+
+ public CreateIndexExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax, IndexDefinition index)
+ : base(current, databaseProviders, sqlSyntax)
{
- Index = new IndexDefinition();
+ Index = index;
}
-
+
public CreateIndexExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
: base(current, databaseProviders, sqlSyntax)
{
Index = new IndexDefinition();
}
-
- [Obsolete("Use alternate ctor specifying ISqlSyntaxProvider instead")]
- public CreateIndexExpression()
- : this(SqlSyntaxContext.SqlSyntaxProvider)
- {
-
- }
-
- [Obsolete("Use alternate ctor specifying ISqlSyntaxProvider instead")]
- public CreateIndexExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders)
- : this(current, databaseProviders, SqlSyntaxContext.SqlSyntaxProvider)
- {
- }
-
- public virtual IndexDefinition Index { get; set; }
+
+ public IndexDefinition Index { get; set; }
public override string ToString()
{
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/IfDatabase/IfDatabaseBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/IfDatabase/IfDatabaseBuilder.cs
index b7105170f1..e0d20c4875 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/IfDatabase/IfDatabaseBuilder.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/IfDatabase/IfDatabaseBuilder.cs
@@ -3,43 +3,46 @@ using Umbraco.Core.Persistence.Migrations.Syntax.Delete;
using Umbraco.Core.Persistence.Migrations.Syntax.Execute;
using Umbraco.Core.Persistence.Migrations.Syntax.Rename;
using Umbraco.Core.Persistence.Migrations.Syntax.Update;
+using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Syntax.IfDatabase
{
public class IfDatabaseBuilder : IIfDatabaseBuilder
{
private readonly IMigrationContext _context;
+ private readonly ISqlSyntaxProvider _sqlSyntax;
private readonly DatabaseProviders[] _databaseProviders;
- public IfDatabaseBuilder(IMigrationContext context, params DatabaseProviders[] databaseProviders)
+ public IfDatabaseBuilder(IMigrationContext context, ISqlSyntaxProvider sqlSyntax, params DatabaseProviders[] databaseProviders)
{
_context = context;
+ _sqlSyntax = sqlSyntax;
_databaseProviders = databaseProviders;
}
public ICreateBuilder Create
{
- get { return new CreateBuilder(_context, _databaseProviders); }
+ get { return new CreateBuilder(_context, _sqlSyntax, _databaseProviders); }
}
public IExecuteBuilder Execute
{
- get { return new ExecuteBuilder(_context, _databaseProviders); }
+ get { return new ExecuteBuilder(_context, _sqlSyntax, _databaseProviders); }
}
public IDeleteBuilder Delete
{
- get { return new DeleteBuilder(_context, _databaseProviders); }
+ get { return new DeleteBuilder(_context, _sqlSyntax, _databaseProviders); }
}
public IRenameBuilder Rename
{
- get { return new RenameBuilder(_context, _databaseProviders); }
+ get { return new RenameBuilder(_context, _sqlSyntax, _databaseProviders); }
}
public IUpdateBuilder Update
{
- get { return new UpdateBuilder(_context, _databaseProviders); }
+ get { return new UpdateBuilder(_context, _sqlSyntax, _databaseProviders); }
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/Expressions/InsertDataExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/Expressions/InsertDataExpression.cs
index 568087733b..28b8c71d39 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/Expressions/InsertDataExpression.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/Expressions/InsertDataExpression.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Text;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.SqlSyntax;
@@ -8,56 +9,76 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Insert.Expressions
public class InsertDataExpression : MigrationExpressionBase
{
private readonly List _rows = new List();
-
- public InsertDataExpression()
- {
- }
-
- public InsertDataExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders) : base(current, databaseProviders)
+
+ public InsertDataExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
+ : base(current, databaseProviders, sqlSyntax)
{
}
public string SchemaName { get; set; }
public string TableName { get; set; }
+ public bool EnabledIdentityInsert { get; set; }
-
public List Rows
{
get { return _rows; }
}
-
-
public override string ToString()
{
- //TODO: This works for single insertion entries, not sure if it is valid for bulk insert operations!!!
-
if (IsExpressionSupported() == false)
return string.Empty;
-
- var insertItems = new List();
- foreach (var item in Rows)
+ var sb = new StringBuilder();
+
+ if (EnabledIdentityInsert && SqlSyntax.SupportsIdentityInsert())
{
- var cols = "";
- var vals = "";
- foreach (var keyVal in item)
+ sb.AppendLine(string.Format("SET IDENTITY_INSERT {0} ON;", SqlSyntax.GetQuotedTableName(TableName)));
+ if (CurrentDatabaseProvider == DatabaseProviders.SqlServer || CurrentDatabaseProvider == DatabaseProviders.SqlServerCE)
{
- cols += keyVal.Key + ",";
- vals += GetQuotedValue(keyVal.Value) + ",";
+ sb.AppendLine("GO");
}
- cols = cols.TrimEnd(',');
- vals = vals.TrimEnd(',');
-
-
- var sql = string.Format(SqlSyntaxContext.SqlSyntaxProvider.InsertData,
- SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName),
- cols, vals);
-
- insertItems.Add(sql);
}
- return string.Join(",", insertItems);
+ try
+ {
+ foreach (var item in Rows)
+ {
+ var cols = "";
+ var vals = "";
+ foreach (var keyVal in item)
+ {
+ cols += SqlSyntax.GetQuotedColumnName(keyVal.Key) + ",";
+ vals += GetQuotedValue(keyVal.Value) + ",";
+ }
+ cols = cols.TrimEnd(',');
+ vals = vals.TrimEnd(',');
+
+
+ var sql = string.Format(SqlSyntax.InsertData,
+ SqlSyntax.GetQuotedTableName(TableName),
+ cols, vals);
+
+ sb.AppendLine(string.Format("{0};", sql));
+ if (CurrentDatabaseProvider == DatabaseProviders.SqlServer || CurrentDatabaseProvider == DatabaseProviders.SqlServerCE)
+ {
+ sb.AppendLine("GO");
+ }
+ }
+ }
+ finally
+ {
+ if (EnabledIdentityInsert && SqlSyntax.SupportsIdentityInsert())
+ {
+ sb.AppendLine(string.Format("SET IDENTITY_INSERT {0} OFF;", SqlSyntax.GetQuotedTableName(TableName)));
+ if (CurrentDatabaseProvider == DatabaseProviders.SqlServer || CurrentDatabaseProvider == DatabaseProviders.SqlServerCE)
+ {
+ sb.AppendLine("GO");
+ }
+ }
+ }
+
+ return sb.ToString();
}
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/IInsertDataSyntax.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/IInsertDataSyntax.cs
index fb0585f0e6..5791f0cb83 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/IInsertDataSyntax.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/IInsertDataSyntax.cs
@@ -2,6 +2,7 @@
{
public interface IInsertDataSyntax : IFluentSyntax
{
+ IInsertDataSyntax EnableIdentityInsert();
IInsertDataSyntax Row(object dataAsAnonymousType);
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/InsertBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/InsertBuilder.cs
index 889c3e4008..2d3ce9c64d 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/InsertBuilder.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/InsertBuilder.cs
@@ -1,19 +1,24 @@
using Umbraco.Core.Persistence.Migrations.Syntax.Insert.Expressions;
+using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Syntax.Insert
{
public class InsertBuilder : IInsertBuilder
{
private readonly IMigrationContext _context;
+ private readonly ISqlSyntaxProvider _sqlSyntax;
+ private readonly DatabaseProviders[] _databaseProviders;
- public InsertBuilder(IMigrationContext context)
+ public InsertBuilder(IMigrationContext context, ISqlSyntaxProvider sqlSyntax, params DatabaseProviders[] databaseProviders)
{
_context = context;
+ _sqlSyntax = sqlSyntax;
+ _databaseProviders = databaseProviders;
}
public IInsertDataSyntax IntoTable(string tableName)
{
- var expression = new InsertDataExpression { TableName = tableName };
+ var expression = new InsertDataExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax) { TableName = tableName };
_context.Expressions.Add(expression);
return new InsertDataBuilder(expression);
}
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/InsertDataBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/InsertDataBuilder.cs
index 9b419f8daf..4f8bf2dfcc 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/InsertDataBuilder.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/InsertDataBuilder.cs
@@ -14,6 +14,12 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Insert
_expression = expression;
}
+ public IInsertDataSyntax EnableIdentityInsert()
+ {
+ _expression.EnabledIdentityInsert = true;
+ return this;
+ }
+
public IInsertDataSyntax Row(object dataAsAnonymousType)
{
_expression.Rows.Add(GetData(dataAsAnonymousType));
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/Expressions/RenameColumnExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/Expressions/RenameColumnExpression.cs
index 4f626e2117..1f84401923 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/Expressions/RenameColumnExpression.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/Expressions/RenameColumnExpression.cs
@@ -3,13 +3,9 @@
namespace Umbraco.Core.Persistence.Migrations.Syntax.Rename.Expressions
{
public class RenameColumnExpression : MigrationExpressionBase
- {
- public RenameColumnExpression()
- {
- }
-
- public RenameColumnExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders)
- : base(current, databaseProviders)
+ {
+ public RenameColumnExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
+ : base(current, databaseProviders, sqlSyntax)
{
}
@@ -52,7 +48,7 @@ SELECT CONCAT(
if (IsExpressionSupported() == false)
return string.Empty;
- return SqlSyntaxContext.SqlSyntaxProvider.FormatColumnRename(TableName, OldName, NewName);
+ return SqlSyntax.FormatColumnRename(TableName, OldName, NewName);
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/Expressions/RenameTableExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/Expressions/RenameTableExpression.cs
index 956cc32bfc..ec60117d7e 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/Expressions/RenameTableExpression.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/Expressions/RenameTableExpression.cs
@@ -4,12 +4,8 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Rename.Expressions
{
public class RenameTableExpression : MigrationExpressionBase
{
- public RenameTableExpression()
- {
- }
-
- public RenameTableExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders)
- : base(current, databaseProviders)
+ public RenameTableExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
+ : base(current, databaseProviders, sqlSyntax)
{
}
@@ -22,7 +18,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Rename.Expressions
if (IsExpressionSupported() == false)
return string.Empty;
- return SqlSyntaxContext.SqlSyntaxProvider.FormatTableRename(OldName, NewName);
+ return SqlSyntax.FormatTableRename(OldName, NewName);
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/RenameBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/RenameBuilder.cs
index 7116935d77..ebfb08b862 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/RenameBuilder.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/RenameBuilder.cs
@@ -1,34 +1,33 @@
using Umbraco.Core.Persistence.Migrations.Syntax.Rename.Column;
using Umbraco.Core.Persistence.Migrations.Syntax.Rename.Expressions;
using Umbraco.Core.Persistence.Migrations.Syntax.Rename.Table;
+using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Syntax.Rename
{
public class RenameBuilder : IRenameBuilder
{
private readonly IMigrationContext _context;
+ private readonly ISqlSyntaxProvider _sqlSyntax;
private readonly DatabaseProviders[] _databaseProviders;
- public RenameBuilder(IMigrationContext context, params DatabaseProviders[] databaseProviders)
+ public RenameBuilder(IMigrationContext context, ISqlSyntaxProvider sqlSyntax, params DatabaseProviders[] databaseProviders)
{
_context = context;
+ _sqlSyntax = sqlSyntax;
_databaseProviders = databaseProviders;
}
public IRenameTableSyntax Table(string oldName)
{
- var expression = _databaseProviders == null
- ? new RenameTableExpression {OldName = oldName}
- : new RenameTableExpression(_context.CurrentDatabaseProvider, _databaseProviders) { OldName = oldName };
+ var expression = new RenameTableExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax) { OldName = oldName };
_context.Expressions.Add(expression);
return new RenameTableBuilder(expression);
}
public IRenameColumnTableSyntax Column(string oldName)
{
- var expression = _databaseProviders == null
- ? new RenameColumnExpression {OldName = oldName}
- : new RenameColumnExpression(_context.CurrentDatabaseProvider, _databaseProviders) { OldName = oldName };
+ var expression = new RenameColumnExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax) { OldName = oldName };
_context.Expressions.Add(expression);
return new RenameColumnBuilder(expression);
}
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Update/Expressions/UpdateDataExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Update/Expressions/UpdateDataExpression.cs
index fd470dd7f2..18bec8b938 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Update/Expressions/UpdateDataExpression.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Update/Expressions/UpdateDataExpression.cs
@@ -5,11 +5,8 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Update.Expressions
{
public class UpdateDataExpression : MigrationExpressionBase
{
- public UpdateDataExpression()
- {
- }
-
- public UpdateDataExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders) : base(current, databaseProviders)
+ public UpdateDataExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
+ : base(current, databaseProviders, sqlSyntax)
{
}
@@ -31,7 +28,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Update.Expressions
foreach (var item in Set)
{
updateItems.Add(string.Format("{0} = {1}",
- SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(item.Key),
+ SqlSyntax.GetQuotedColumnName(item.Key),
GetQuotedValue(item.Value)));
}
@@ -44,13 +41,13 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Update.Expressions
foreach (var item in Where)
{
whereClauses.Add(string.Format("{0} {1} {2}",
- SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(item.Key),
+ SqlSyntax.GetQuotedColumnName(item.Key),
item.Value == null ? "IS" : "=",
GetQuotedValue(item.Value)));
}
}
- return string.Format(SqlSyntaxContext.SqlSyntaxProvider.UpdateData,
- SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName),
+ return string.Format(SqlSyntax.UpdateData,
+ SqlSyntax.GetQuotedTableName(TableName),
string.Join(", ", updateItems.ToArray()),
string.Join(" AND ", whereClauses.ToArray()));
}
diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Update/UpdateBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Update/UpdateBuilder.cs
index e2e118c05f..3816e65132 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Update/UpdateBuilder.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Update/UpdateBuilder.cs
@@ -1,23 +1,24 @@
using Umbraco.Core.Persistence.Migrations.Syntax.Update.Expressions;
+using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Syntax.Update
{
public class UpdateBuilder : IUpdateBuilder
{
private readonly IMigrationContext _context;
+ private readonly ISqlSyntaxProvider _sqlSyntax;
private readonly DatabaseProviders[] _databaseProviders;
- public UpdateBuilder(IMigrationContext context, params DatabaseProviders[] databaseProviders)
+ public UpdateBuilder(IMigrationContext context, ISqlSyntaxProvider sqlSyntax, params DatabaseProviders[] databaseProviders)
{
_context = context;
+ _sqlSyntax = sqlSyntax;
_databaseProviders = databaseProviders;
}
public IUpdateSetSyntax Table(string tableName)
{
- var expression = _databaseProviders == null
- ? new UpdateDataExpression { TableName = tableName }
- : new UpdateDataExpression(_context.CurrentDatabaseProvider, _databaseProviders) { TableName = tableName };
+ var expression = new UpdateDataExpression(_context.CurrentDatabaseProvider, _databaseProviders, _sqlSyntax) { TableName = tableName };
_context.Expressions.Add(expression);
return new UpdateDataBuilder(expression, _context);
}
diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSeven/AddIndexToCmsMacroTable.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSeven/AddIndexToCmsMacroTable.cs
index 4ca0a6eeb8..d18cb430c0 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSeven/AddIndexToCmsMacroTable.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSeven/AddIndexToCmsMacroTable.cs
@@ -3,6 +3,7 @@ using System.CodeDom;
using System.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
+using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.SqlSyntax;
@@ -14,12 +15,12 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven
[Migration("7.0.0", 4, GlobalSettings.UmbracoMigrationName)]
public class AddIndexToCmsMacroTable : MigrationBase
{
- private readonly bool _skipIndexCheck;
+ private readonly bool _forTesting;
- internal AddIndexToCmsMacroTable(bool skipIndexCheck, ISqlSyntaxProvider sqlSyntax, ILogger logger)
+ internal AddIndexToCmsMacroTable(bool forTesting, ISqlSyntaxProvider sqlSyntax, ILogger logger)
: base(sqlSyntax, logger)
{
- _skipIndexCheck = skipIndexCheck;
+ _forTesting = forTesting;
}
public AddIndexToCmsMacroTable(ISqlSyntaxProvider sqlSyntax, ILogger logger) : base(sqlSyntax, logger)
@@ -28,7 +29,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven
public override void Up()
{
- var dbIndexes = _skipIndexCheck ? new DbIndexDefinition[] { } : SqlSyntax.GetDefinedIndexes(Context.Database)
+ var dbIndexes = _forTesting ? new DbIndexDefinition[] { } : SqlSyntax.GetDefinedIndexes(Context.Database)
.Select(x => new DbIndexDefinition()
{
TableName = x.Item1,
@@ -40,6 +41,30 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven
//make sure it doesn't already exist
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsMacro_Alias")) == false)
{
+ //in order to create this index, we need to ensure that there are no duplicates. This could have happened with very old/corrupt umbraco versions.
+ // So we'll remove any duplicates based on alias and only keep the one with the smallest id since I'm pretty sure we'd always choose the 'first' one
+ // when running a query.
+
+ if (_forTesting == false)
+ {
+ //NOTE: Using full SQL statement here in case the DTO has changed between versions
+ var macros = Context.Database.Fetch("SELECT * FROM cmsMacro")
+ .GroupBy(x => x.Alias)
+ .Where(x => x.Count() > 1);
+
+ foreach (var m in macros)
+ {
+ //get the min id (to keep)
+ var minId = m.Min(x => x.Id);
+ //delete all the others
+ foreach (var macroDto in m.Where(x => x.Id != minId))
+ {
+ Delete.FromTable("cmsMacro").Row(new { id = macroDto.Id });
+ }
+ }
+ }
+
+
Create.Index("IX_cmsMacro_Alias").OnTable("cmsMacro").OnColumn("macroAlias").Unique();
}
diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSeven/AlterTagsTable.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSeven/AlterTagsTable.cs
index 6060b76fa4..d069d8222d 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSeven/AlterTagsTable.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSeven/AlterTagsTable.cs
@@ -27,6 +27,11 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven
}).ToArray();
//add a foreign key to the parent id column too!
+
+ //In some cases in very old corrupted db's this will fail, so it means we need to clean the data first
+ //set the parentID to NULL where it doesn't actually exist in the normal ids
+ Execute.Sql(@"UPDATE cmsTags SET parentId = NULL WHERE parentId IS NOT NULL AND parentId NOT IN (SELECT id FROM cmsTags)");
+
Create.ForeignKey("FK_cmsTags_cmsTags")
.FromTable("cmsTags")
.ForeignColumn("ParentId")
diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSeven/UpdateRelatedLinksData.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSeven/UpdateRelatedLinksData.cs
index a2e2056d3a..830adfd7fb 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSeven/UpdateRelatedLinksData.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSeven/UpdateRelatedLinksData.cs
@@ -55,9 +55,11 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven
}
var propertyTypeIds = propertyData.Select(x => x.PropertyTypeId).Distinct();
- var propertyTypes = database.Fetch(
- "WHERE id in (@propertyTypeIds)", new { propertyTypeIds = propertyTypeIds });
+ //NOTE: We are writing the full query because we've added a column to the PropertyTypeDto in later versions so one of the columns
+ // won't exist yet
+ var propertyTypes = database.Fetch("SELECT * FROM cmsPropertyType WHERE id in (@propertyTypeIds)", new { propertyTypeIds = propertyTypeIds });
+
foreach (var data in propertyData)
{
if (string.IsNullOrEmpty(data.Text) == false)
diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/AddForeignKeysForLanguageAndDictionaryTables.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/AddForeignKeysForLanguageAndDictionaryTables.cs
index 81b93a8883..eea56031d4 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/AddForeignKeysForLanguageAndDictionaryTables.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/AddForeignKeysForLanguageAndDictionaryTables.cs
@@ -3,6 +3,8 @@ using System.Data;
using System.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
+using Umbraco.Core.Models.Rdbms;
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZero
@@ -30,6 +32,53 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZe
Delete.FromTable("cmsLanguageText").Row(new { pk = pk });
}
+ var columns = SqlSyntax.GetColumnsInSchema(Context.Database).Distinct().ToArray();
+
+ if (columns.Any(x => x.ColumnName.InvariantEquals("id")
+ && x.TableName.InvariantEquals("umbracoLanguage")
+ && x.DataType.InvariantEquals("smallint")))
+ {
+ //Ensure that the umbracoLanguage PK is INT and not SmallInt (which it might be in older db versions)
+ // In order to 'change' this to an INT, we have to run a full migration script which is super annoying
+ Create.Table("umbracoLanguage_TEMP")
+ .WithColumn("id").AsInt32().NotNullable().Identity()
+ .WithColumn("languageISOCode").AsString(10).Nullable()
+ .WithColumn("languageCultureName").AsString(50).Nullable();
+
+ var currentData = this.Context.Database.Fetch(new Sql().Select("*").From(SqlSyntax));
+ foreach (var languageDto in currentData)
+ {
+ Insert.IntoTable("umbracoLanguage_TEMP")
+ .EnableIdentityInsert()
+ .Row(new {id = languageDto.Id, languageISOCode = languageDto.IsoCode, languageCultureName = languageDto.CultureName});
+ }
+
+ //ok, all data has been copied over, drop the old table, rename the temp table and re-add constraints.
+ Delete.Table("umbracoLanguage");
+ Rename.Table("umbracoLanguage_TEMP").To("umbracoLanguage");
+
+ //add the pk
+ Create.PrimaryKey("PK_language").OnTable("umbracoLanguage").Column("id");
+ }
+
+ var dbIndexes = SqlSyntax.GetDefinedIndexes(Context.Database)
+ .Select(x => new DbIndexDefinition
+ {
+ TableName = x.Item1,
+ IndexName = x.Item2,
+ ColumnName = x.Item3,
+ IsUnique = x.Item4
+ }).ToArray();
+
+ //make sure it doesn't already exist
+ if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsDictionary_id")) == false)
+ {
+ Create.Index("IX_cmsDictionary_id").OnTable("cmsDictionary")
+ .OnColumn("id").Ascending()
+ .WithOptions().NonClustered()
+ .WithOptions().Unique();
+ }
+
//now we need to create a foreign key
Create.ForeignKey("FK_cmsLanguageText_umbracoLanguage_id").FromTable("cmsLanguageText").ForeignColumn("languageId")
.ToTable("umbracoLanguage").PrimaryColumn("id").OnDeleteOrUpdate(Rule.None);
@@ -52,7 +101,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZe
public override void Down()
{
- throw new System.NotImplementedException();
+ throw new NotImplementedException();
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/AddServerRegistrationColumnsAndLock.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/AddServerRegistrationColumnsAndLock.cs
new file mode 100644
index 0000000000..118dc1fc06
--- /dev/null
+++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/AddServerRegistrationColumnsAndLock.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Linq;
+using Umbraco.Core.Configuration;
+using Umbraco.Core.Logging;
+using Umbraco.Core.Models.Rdbms;
+using Umbraco.Core.Persistence.SqlSyntax;
+
+namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZero
+{
+ [Migration("7.3.0", 17, GlobalSettings.UmbracoMigrationName)]
+ public class AddServerRegistrationColumnsAndLock : MigrationBase
+ {
+ public AddServerRegistrationColumnsAndLock(ISqlSyntaxProvider sqlSyntax, ILogger logger)
+ : base(sqlSyntax, logger)
+ { }
+
+ public override void Up()
+ {
+ // don't execute if the column is already there
+ var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
+ if (columns.Any(x => x.TableName.InvariantEquals("umbracoServer") && x.ColumnName.InvariantEquals("isMaster")) == false)
+ {
+ Create.Column("isMaster").OnTable("umbracoServer").AsBoolean().NotNullable().WithDefaultValue(0);
+ }
+
+ EnsureLockObject(Constants.System.ServersLock, "0AF5E610-A310-4B6F-925F-E928D5416AF7", "LOCK: Servers");
+ }
+
+ public override void Down()
+ {
+ // not implemented
+ }
+
+ private void EnsureLockObject(int id, string uniqueId, string text)
+ {
+ var exists = Context.Database.Exists(id);
+ if (exists) return;
+
+ Insert
+ .IntoTable("umbracoNode")
+ .EnableIdentityInsert()
+ .Row(new
+ {
+ id = id, // NodeId
+ trashed = false,
+ parentId = -1,
+ nodeUser = 0,
+ level = 1,
+ path = "-1," + id,
+ sortOrder = 0,
+ uniqueId = new Guid(uniqueId),
+ text = text,
+ nodeObjectType = new Guid(Constants.ObjectTypes.LockObject),
+ createDate = DateTime.Now
+ });
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/CleanUpCorruptedPublishedFlags.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/CleanUpCorruptedPublishedFlags.cs
new file mode 100644
index 0000000000..d62ad7645d
--- /dev/null
+++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/CleanUpCorruptedPublishedFlags.cs
@@ -0,0 +1,49 @@
+using System.Linq;
+using Umbraco.Core.Configuration;
+using Umbraco.Core.Logging;
+using Umbraco.Core.Models.Rdbms;
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
+using Umbraco.Core.Persistence.SqlSyntax;
+
+namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZero
+{
+ ///
+ /// Older corrupted dbs might have multiple published flags for a content item, this shouldn't be possible
+ /// so we need to clear the content flag on the older version
+ ///
+ [Migration("7.3.0", 18, GlobalSettings.UmbracoMigrationName)]
+ public class CleanUpCorruptedPublishedFlags : MigrationBase
+ {
+ public CleanUpCorruptedPublishedFlags(ISqlSyntaxProvider sqlSyntax, ILogger logger)
+ : base(sqlSyntax, logger)
+ {
+ }
+
+ public override void Up()
+ {
+ //Get all cmsDocument items that have more than one published date set
+ var sql = @"SELECT * FROM cmsDocument WHERE nodeId IN
+(SELECT nodeId
+FROM cmsDocument
+GROUP BY nodeId
+HAVING SUM(CASE WHEN published = 0 THEN 0 ELSE 1 END) > 1)
+AND published = 1
+ORDER BY nodeId, updateDate";
+
+ var docs = Context.Database.Fetch(sql).GroupBy(x => x.NodeId);
+
+ foreach (var doc in docs)
+ {
+ var latest = doc.OrderByDescending(x => x.UpdateDate).First();
+ foreach (var old in doc.Where(x => x.VersionId != latest.VersionId))
+ {
+ Update.Table("cmsDocument").Set(new {published = 0}).Where(new {nodeId = old.NodeId});
+ }
+ }
+ }
+
+ public override void Down()
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/CreateCacheInstructionTable.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/CreateCacheInstructionTable.cs
index 00f968941d..afa5a1e675 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/CreateCacheInstructionTable.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/CreateCacheInstructionTable.cs
@@ -28,14 +28,11 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZe
var textType = SqlSyntax.GetSpecialDbType(SpecialDbTypes.NTEXT);
Create.Table("umbracoCacheInstruction")
- .WithColumn("id").AsInt32().Identity().NotNullable()
+ .WithColumn("id").AsInt32().NotNullable().PrimaryKey("PK_umbracoCacheInstruction").Identity()
.WithColumn("utcStamp").AsDateTime().NotNullable()
.WithColumn("jsonInstruction").AsCustom(textType).NotNullable()
.WithColumn("originated").AsString(500).NotNullable();
-
- Create.PrimaryKey("PK_umbracoCacheInstruction")
- .OnTable("umbracoCacheInstruction")
- .Column("id");
+
}
public override void Down()
diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/MigrateAndRemoveTemplateMasterColumn.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/MigrateAndRemoveTemplateMasterColumn.cs
index 3cea873f73..cb0ad58a49 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/MigrateAndRemoveTemplateMasterColumn.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/MigrateAndRemoveTemplateMasterColumn.cs
@@ -23,34 +23,92 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZe
{
//Don't execute anything if there is no 'master' column - this might occur if the db is already upgraded
- var cols = SqlSyntax.GetColumnsInSchema(Context.Database);
+ var cols = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
if (cols.Any(x => x.ColumnName.InvariantEquals("master") && x.TableName.InvariantEquals("cmsTemplate")) == false)
{
return;
}
+
+ var constraints = SqlSyntax.GetConstraintsPerColumn(Context.Database).Distinct().ToArray();
//update the parentId column for all templates to be correct so it matches the current 'master' template
- //NOTE: we are using dynamic because we need to get the data in a column that no longer exists in the schema
- var templates = Context.Database.Fetch(new Sql().Select("*").From());
- foreach (var template in templates)
- {
- Update.Table("umbracoNode").Set(new {parentID = template.master ?? -1}).Where(new {id = template.nodeId});
- //now build the correct path for the template
- Update.Table("umbracoNode").Set(new { path = BuildPath (template, templates)}).Where(new { id = template.nodeId });
-
- }
+ //In some old corrupted databases, the information will not be correct in the master column so we need to fix that
+ //first by nulling out the master column where the id doesn't actually exist
+ Execute.Sql(@"UPDATE cmsTemplate SET master = NULL WHERE " +
+ SqlSyntax.GetQuotedColumnName("master") + @" IS NOT NULL AND " +
+ SqlSyntax.GetQuotedColumnName("master") + @" NOT IN (" +
+ //Stupid MySQL... needs this stupid syntax because it can do an update with a sub query of itself,
+ // yet it can do one with a sub sub query
+ // ... this will work in all dbs too
+ @"SELECT nodeId FROM (SELECT * FROM cmsTemplate a) b)");
+
+ //Now we can bulk update the parentId column
+
+ //NOTE: This single statement should be used but stupid SQLCE doesn't support Update with a FROM !!
+ // so now we have to do this by individual rows :(
+ //Execute.Sql(@"UPDATE umbracoNode
+ //SET parentID = COALESCE(t2." + SqlSyntax.GetQuotedColumnName("master") + @", -1)
+ //FROM umbracoNode t1
+ //INNER JOIN cmsTemplate t2
+ //ON t1.id = t2.nodeId");
+ Execute.Code(database =>
+ {
+ var templateData = database.Fetch("SELECT * FROM cmsTemplate");
+
+ foreach (var template in templateData)
+ {
+ var sql = "SET parentID=@parentId WHERE id=@nodeId";
+
+ LogHelper.Info("Executing sql statement: UPDATE umbracoNode " + sql);
+
+ database.Update(sql,
+ new {parentId = template.master ?? -1, nodeId = template.nodeId});
+ }
+
+ return string.Empty;
+ });
+
+ //Now we can update the path, but this needs to be done in a delegate callback so that the query runs after the updates just completed
+ Execute.Code(database =>
+ {
+ //NOTE: we are using dynamic because we need to get the data in a column that no longer exists in the schema
+ var templates = database.Fetch(new Sql().Select("*").From());
+ foreach (var template in templates)
+ {
+ var sql = string.Format(SqlSyntax.UpdateData,
+ SqlSyntax.GetQuotedTableName("umbracoNode"),
+ "path=@buildPath",
+ "id=@nodeId");
+
+ LogHelper.Info("Executing sql statement: " + sql);
+
+ //now build the correct path for the template
+ database.Execute(sql, new
+ {
+ buildPath = BuildPath(template, templates),
+ nodeId = template.nodeId
+ });
+ }
+
+ return string.Empty;
+ });
+
+
//now remove the master column and key
if (this.Context.CurrentDatabaseProvider == DatabaseProviders.MySql)
{
- Delete.ForeignKey().FromTable("cmsTemplate").ForeignColumn("master").ToTable("umbracoUser").PrimaryColumn("id");
+ //Because MySQL doesn't name keys with what you want, we need to query for the one that is associated
+ // this is required for this specific case because there are 2 foreign keys on the cmsTemplate table
+ var fkName = constraints.FirstOrDefault(x => x.Item1.InvariantEquals("cmsTemplate") && x.Item2.InvariantEquals("master"));
+ if (fkName != null)
+ {
+ Delete.ForeignKey(fkName.Item3).OnTable("cmsTemplate");
+ }
}
else
{
- //These are the old aliases, before removing them, check they exist
- var constraints = SqlSyntax.GetConstraintsPerColumn(Context.Database).Distinct().ToArray();
-
if (constraints.Any(x => x.Item1.InvariantEquals("cmsTemplate") && x.Item3.InvariantEquals("FK_cmsTemplate_cmsTemplate")))
{
Delete.ForeignKey("FK_cmsTemplate_cmsTemplate").OnTable("cmsTemplate");
@@ -59,8 +117,8 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZe
//TODO: Hopefully it's not named something else silly in some crazy old versions
}
- var columns = SqlSyntax.GetColumnsInSchema(Context.Database).Distinct().ToArray();
- if (columns.Any(x => x.ColumnName.InvariantEquals("master") && x.TableName.InvariantEquals("cmsTemplate")))
+
+ if (cols.Any(x => x.ColumnName.InvariantEquals("master") && x.TableName.InvariantEquals("cmsTemplate")))
{
Delete.Column("master").FromTable("cmsTemplate");
}
diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixZeroOne/UpdatePropertyTypesAndGroups.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixZeroOne/UpdatePropertyTypesAndGroups.cs
index 5f27bfa4f5..6598719454 100644
--- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixZeroOne/UpdatePropertyTypesAndGroups.cs
+++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixZeroOne/UpdatePropertyTypesAndGroups.cs
@@ -28,8 +28,11 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixZeroOne
{
if (database != null)
{
- //Fetch all PropertyTypes that belongs to a PropertyTypeGroup
- var propertyTypes = database.Fetch("WHERE propertyTypeGroupId > 0");
+ //Fetch all PropertyTypes that belongs to a PropertyTypeGroup
+ //NOTE: We are writing the full query because we've added a column to the PropertyTypeDto in later versions so one of the columns
+ // won't exist yet
+ var propertyTypes = database.Fetch("SELECT * FROM cmsPropertyType WHERE propertyTypeGroupId > 0");
+
var propertyGroups = database.Fetch("WHERE id > 0");
foreach (var propertyType in propertyTypes)
diff --git a/src/Umbraco.Core/Persistence/PetaPoco.cs b/src/Umbraco.Core/Persistence/PetaPoco.cs
index 42ab8ab610..d55ad8fc14 100644
--- a/src/Umbraco.Core/Persistence/PetaPoco.cs
+++ b/src/Umbraco.Core/Persistence/PetaPoco.cs
@@ -215,6 +215,10 @@ namespace Umbraco.Core.Persistence
_paramPrefix = "?";
if (_dbType == DBType.Oracle)
_paramPrefix = ":";
+
+ // by default use MSSQL default ReadCommitted level
+ //TODO change to RepeatableRead - but that is breaking
+ _isolationLevel = IsolationLevel.ReadCommitted;
}
// Automatically close one open shared connection
@@ -237,7 +241,27 @@ namespace Umbraco.Core.Persistence
_sharedConnection.ConnectionString = _connectionString;
_sharedConnection.OpenWithRetry();//Changed .Open() => .OpenWithRetry() extension method
- _sharedConnection = OnConnectionOpened(_sharedConnection);
+ // ensure we have the proper isolation level, as levels can leak in pools
+ // read http://stackoverflow.com/questions/9851415/sql-server-isolation-level-leaks-across-pooled-connections
+ // and http://stackoverflow.com/questions/641120/what-exec-sp-reset-connection-shown-in-sql-profiler-means
+ //
+ // NPoco has that code in OpenSharedConnectionImp (commented out?)
+ //using (var cmd = _sharedConnection.CreateCommand())
+ //{
+ // cmd.CommandText = GetSqlForTransactionLevel(_isolationLevel);
+ // cmd.CommandTimeout = CommandTimeout;
+ // cmd.ExecuteNonQuery();
+ //}
+ //
+ // although MSDN documentation for SQL CE clearly states that the above method
+ // should work, it fails & reports an error parsing the query on 'TRANSACTION',
+ // and Google is no help (others have faced the same issue... no solution). So,
+ // switching to another method that does work on all databases.
+ var tr = _sharedConnection.BeginTransaction(_isolationLevel);
+ tr.Commit();
+ tr.Dispose();
+
+ _sharedConnection = OnConnectionOpened(_sharedConnection);
if (KeepConnectionAlive)
_sharedConnectionDepth++; // Make sure you call Dispose
@@ -269,10 +293,20 @@ namespace Umbraco.Core.Persistence
// Helper to create a transaction scope
public Transaction GetTransaction()
{
- return new Transaction(this);
- }
+ return GetTransaction(_isolationLevel);
+ }
- // Use by derived repo generated by T4 templates
+ public Transaction GetTransaction(IsolationLevel isolationLevel)
+ {
+ return new Transaction(this, isolationLevel);
+ }
+
+ public IsolationLevel CurrentTransactionIsolationLevel
+ {
+ get { return _transaction == null ? IsolationLevel.Unspecified : _transaction.IsolationLevel; }
+ }
+
+ // Use by derived repo generated by T4 templates
public virtual void OnBeginTransaction() { }
public virtual void OnEndTransaction() { }
@@ -281,17 +315,23 @@ namespace Umbraco.Core.Persistence
// Use `using (var scope=db.Transaction) { scope.Complete(); }` to ensure correct semantics
public void BeginTransaction()
{
- _transactionDepth++;
+ BeginTransaction(_isolationLevel);
+ }
+
+ public void BeginTransaction(IsolationLevel isolationLevel)
+ {
+ _transactionDepth++;
if (_transactionDepth == 1)
{
OpenSharedConnection();
- _transaction = _sharedConnection.BeginTransaction();
+ _transaction = _sharedConnection.BeginTransaction(isolationLevel);
_transactionCancelled = false;
OnBeginTransaction();
}
-
- }
+ else if (isolationLevel > _transaction.IsolationLevel)
+ throw new Exception("Already in a transaction with a lower isolation level.");
+ }
// Internal helper to cleanup transaction stuff
void CleanupTransaction()
@@ -313,6 +353,7 @@ namespace Umbraco.Core.Persistence
public void AbortTransaction()
{
_transactionCancelled = true;
+ //TODO what shall we do if transactionDepth is already zero?
if ((--_transactionDepth) == 0)
CleanupTransaction();
}
@@ -320,11 +361,32 @@ namespace Umbraco.Core.Persistence
// Complete the transaction
public void CompleteTransaction()
{
- if ((--_transactionDepth) == 0)
+ //TODO what shall we do if transactionDepth is already zero?
+ if ((--_transactionDepth) == 0)
CleanupTransaction();
}
- // Helper to handle named parameters from object properties
+ // in NPoco this is in DatabaseType
+ private static string GetSqlForTransactionLevel(IsolationLevel isolationLevel)
+ {
+ switch (isolationLevel)
+ {
+ case IsolationLevel.ReadCommitted:
+ return "SET TRANSACTION ISOLATION LEVEL READ COMMITTED";
+ case IsolationLevel.ReadUncommitted:
+ return "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED";
+ case IsolationLevel.RepeatableRead:
+ return "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ";
+ case IsolationLevel.Serializable:
+ return "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE";
+ case IsolationLevel.Snapshot:
+ return "SET TRANSACTION ISOLATION LEVEL SNAPSHOT";
+ default:
+ return "SET TRANSACTION ISOLATION LEVEL READ COMMITTED";
+ }
+ }
+
+ // Helper to handle named parameters from object properties
static Regex rxParams = new Regex(@"(? args_dest)
{
@@ -2264,16 +2326,17 @@ namespace Umbraco.Core.Persistence
string _lastSql;
object[] _lastArgs;
string _paramPrefix = "@";
+ IsolationLevel _isolationLevel;
}
// Transaction object helps maintain transaction depth counts
public class Transaction : IDisposable
{
- public Transaction(Database db)
- {
- _db = db;
- _db.BeginTransaction();
- }
+ public Transaction(Database db, IsolationLevel isolationLevel)
+ {
+ _db = db;
+ _db.BeginTransaction(isolationLevel);
+ }
public virtual void Complete()
{
@@ -2283,6 +2346,7 @@ namespace Umbraco.Core.Persistence
public void Dispose()
{
+ //TODO prevent multiple calls to Dispose
if (_db != null)
_db.AbortTransaction();
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
index 61e94568e3..60d7d8e7ef 100644
--- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
@@ -654,8 +654,8 @@ namespace Umbraco.Core.Persistence.Repositories
var translator = new SqlTranslator(sqlClause, query);
var sql = translator.Translate()
.Where(x => x.Published)
- .OrderBy(x => x.Level)
- .OrderBy(x => x.SortOrder);
+ .OrderBy(x => x.Level, SqlSyntax)
+ .OrderBy(x => x.SortOrder, SqlSyntax);
//NOTE: This doesn't allow properties to be part of the query
var dtos = Database.Fetch(sql);
@@ -896,7 +896,7 @@ namespace Umbraco.Core.Persistence.Repositories
///
/// Private method to create a content object from a DocumentDto, which is used by Get and GetByVersion.
///
- ///
+ ///
///
///
///
diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs
index 9ac905cf03..c75c061452 100644
--- a/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs
@@ -1130,6 +1130,11 @@ AND umbracoNode.id <> @id",
out IDictionary allPropertyTypeCollection,
out IDictionary allPropertyGroupCollection)
{
+ allPropertyGroupCollection = new Dictionary();
+ allPropertyTypeCollection = new Dictionary();
+
+ // query below is not safe + pointless if array is empty
+ if (contentTypeIds.Length == 0) return;
// first part Gets all property groups including property type data even when no property type exists on the group
// second part Gets all property types including ones that are not on a group
@@ -1165,10 +1170,8 @@ AND umbracoNode.id <> @id",
INNER JOIN cmsDataType as DT
ON PT.dataTypeId = DT.nodeId
LEFT JOIN cmsPropertyTypeGroup as PG
- ON PG.id = PT.propertyTypeGroupId");
-
- if (contentTypeIds.Any())
- sqlBuilder.AppendLine(" WHERE (PT.contentTypeId in (@contentTypeIds))");
+ ON PG.id = PT.propertyTypeGroupId
+ WHERE (PT.contentTypeId in (@contentTypeIds))");
sqlBuilder.AppendLine(" ORDER BY (pgId)");
@@ -1179,9 +1182,6 @@ AND umbracoNode.id <> @id",
var result = db.Fetch(sqlBuilder.ToString(), new { contentTypeIds = contentTypeIds });
- allPropertyGroupCollection = new Dictionary();
- allPropertyTypeCollection = new Dictionary();
-
foreach (var contentTypeId in contentTypeIds)
{
//from this we need to make :
diff --git a/src/Umbraco.Core/Persistence/Repositories/DeepCloneRuntimeCacheProvider.cs b/src/Umbraco.Core/Persistence/Repositories/DeepCloneRuntimeCacheProvider.cs
index a87ec1e764..0b5b42660d 100644
--- a/src/Umbraco.Core/Persistence/Repositories/DeepCloneRuntimeCacheProvider.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/DeepCloneRuntimeCacheProvider.cs
@@ -79,7 +79,7 @@ namespace Umbraco.Core.Persistence.Repositories
public object GetCacheItem(string cacheKey, Func