Merge branch 'dev-v7-contenttypeeditor' of https://github.com/umbraco/Umbraco-CMS into dev-v7-contenttypeeditor

This commit is contained in:
Mads Rasmussen
2015-09-20 15:49:14 +02:00
303 changed files with 5420 additions and 2922 deletions
+3 -3
View File
@@ -32,9 +32,9 @@
<dependency id="ClientDependency-Mvc5" version="[1.8.0, 2.0.0)" />
<dependency id="AutoMapper" version="[3.0.0, 3.1.0)" />
<dependency id="Newtonsoft.Json" version="[6.0.8, 7.0.0)" />
<dependency id="Examine" version="[0.1.66, 1.0.0)" />
<dependency id="ImageProcessor" version="[1.9.5, 3.0.0)" />
<dependency id="ImageProcessor.Web" version="[3.3.1, 5.0.0)" />
<dependency id="Examine" version="[0.1.68, 1.0.0)" />
<dependency id="ImageProcessor" version="[2.2.8, 3.0.0)" />
<dependency id="ImageProcessor.Web" version="[4.3.6, 5.0.0)" />
<dependency id="semver" version="[1.1.2, 2.0.0)" />
<dependency id="Microsoft.AspNet.WebHelpers" version="[3.2.3, 4.0.0)" />
<dependency id="Microsoft.AspNet.WebPages.Data" version="[3.2.3, 4.0.0)" />
+3 -4
View File
@@ -22,10 +22,7 @@
<appSettings>
<add key="owin:appStartup" value="UmbracoDefaultOwinStartup" xdt:Locator="Match(key)" xdt:Transform="InsertIfMissing" />
</appSettings>
<appSettings>
<add key="owin:appStartup" value="UmbracoDefaultOwinStartup" xdt:Locator="Match(key)" xdt:Transform="SetAttributes" />
</appSettings>
<umbracoConfiguration xdt:Transform="InsertIfMissing">
<settings configSource="config\umbracoSettings.config" xdt:Locator="Match(configSource)" xdt:Transform="InsertIfMissing" />
<BaseRestExtensions configSource="config\BaseRestExtensions.config" xdt:Locator="Match(configSource)" xdt:Transform="InsertIfMissing" />
@@ -51,6 +48,8 @@
<system.web xdt:Transform="InsertIfMissing" />
<system.web>
<siteMap xdt:Transform="Remove" />
<httpRuntime xdt:Transform="InsertIfMissing" />
<httpRuntime targetFramework="4.5" xdt:Transform="SetAttributes(targetFramework)" />
<membership defaultProvider="DefaultMembershipProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove" />
<roleManager defaultProvider="DefaultRoleProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove"/>
<profile defaultProvider="DefaultProfileProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove"/>>
+1 -2
View File
@@ -1,3 +1,2 @@
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
7.3.0
beta3
7.3.0
+1 -1
View File
@@ -12,4 +12,4 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.3.0")]
[assembly: AssemblyInformationalVersion("7.3.0-beta3")]
[assembly: AssemblyInformationalVersion("7.3.0")]
+9 -12
View File
@@ -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<bool> _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();
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Configuration
/// Gets the version comment (like beta or RC).
/// </summary>
/// <value>The version comment.</value>
public static string CurrentComment { get { return "beta3"; } }
public static string CurrentComment { get { return ""; } }
// 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
+73 -68
View File
@@ -2,13 +2,13 @@
namespace Umbraco.Core
{
public static partial class Constants
{
/// <summary>
/// Defines the identifiers for Umbraco object types as constants for easy centralized access/management.
/// </summary>
public static class ObjectTypes
{
public static partial class Constants
{
/// <summary>
/// Defines the identifiers for Umbraco object types as constants for easy centralized access/management.
/// </summary>
public static class ObjectTypes
{
/// <summary>
/// Guid for a doc type container
/// </summary>
@@ -19,84 +19,89 @@ namespace Umbraco.Core
/// </summary>
public const string MediaTypeContainer = "42AEF799-B288-4744-9B10-BE144B73CDC4";
/// <summary>
/// Guid for a Content Item object.
/// </summary>
public const string ContentItem = "10E2B09F-C28B-476D-B77A-AA686435E44A";
/// <summary>
/// Guid for a Content Item object.
/// </summary>
public const string ContentItem = "10E2B09F-C28B-476D-B77A-AA686435E44A";
/// <summary>
/// Guid for a Content Item Type object.
/// </summary>
public const string ContentItemType = "7A333C54-6F43-40A4-86A2-18688DC7E532";
/// <summary>
/// Guid for a Content Item Type object.
/// </summary>
public const string ContentItemType = "7A333C54-6F43-40A4-86A2-18688DC7E532";
/// <summary>
/// Guid for the Content Recycle Bin.
/// </summary>
public const string ContentRecycleBin = "01BB7FF2-24DC-4C0C-95A2-C24EF72BBAC8";
/// <summary>
/// Guid for the Content Recycle Bin.
/// </summary>
public const string ContentRecycleBin = "01BB7FF2-24DC-4C0C-95A2-C24EF72BBAC8";
/// <summary>
/// Guid for a DataType object.
/// </summary>
public const string DataType = "30A2A501-1978-4DDB-A57B-F7EFED43BA3C";
/// <summary>
/// Guid for a DataType object.
/// </summary>
public const string DataType = "30A2A501-1978-4DDB-A57B-F7EFED43BA3C";
/// <summary>
/// Guid for a Document object.
/// </summary>
public const string Document = "C66BA18E-EAF3-4CFF-8A22-41B16D66A972";
/// <summary>
/// Guid for a Document object.
/// </summary>
public const string Document = "C66BA18E-EAF3-4CFF-8A22-41B16D66A972";
/// <summary>
/// Guid for a Document Type object.
/// </summary>
public const string DocumentType = "A2CB7800-F571-4787-9638-BC48539A0EFB";
/// <summary>
/// Guid for a Document Type object.
/// </summary>
public const string DocumentType = "A2CB7800-F571-4787-9638-BC48539A0EFB";
/// <summary>
/// Guid for a Media object.
/// </summary>
public const string Media = "B796F64C-1F99-4FFB-B886-4BF4BC011A9C";
/// <summary>
/// Guid for a Media object.
/// </summary>
public const string Media = "B796F64C-1F99-4FFB-B886-4BF4BC011A9C";
/// <summary>
/// Guid for the Media Recycle Bin.
/// </summary>
public const string MediaRecycleBin = "CF3D8E34-1C1C-41e9-AE56-878B57B32113";
/// <summary>
/// Guid for the Media Recycle Bin.
/// </summary>
public const string MediaRecycleBin = "CF3D8E34-1C1C-41e9-AE56-878B57B32113";
/// <summary>
/// Guid for a Media Type object.
/// </summary>
public const string MediaType = "4EA4382B-2F5A-4C2B-9587-AE9B3CF3602E";
/// <summary>
/// Guid for a Media Type object.
/// </summary>
public const string MediaType = "4EA4382B-2F5A-4C2B-9587-AE9B3CF3602E";
/// <summary>
/// Guid for a Member object.
/// </summary>
public const string Member = "39EB0F98-B348-42A1-8662-E7EB18487560";
/// <summary>
/// Guid for a Member object.
/// </summary>
public const string Member = "39EB0F98-B348-42A1-8662-E7EB18487560";
/// <summary>
/// Guid for a Member Group object.
/// </summary>
public const string MemberGroup = "366E63B9-880F-4E13-A61C-98069B029728";
/// <summary>
/// Guid for a Member Group object.
/// </summary>
public const string MemberGroup = "366E63B9-880F-4E13-A61C-98069B029728";
/// <summary>
/// Guid for a Member Type object.
/// </summary>
public const string MemberType = "9B5416FB-E72F-45A9-A07B-5A9A2709CE43";
/// <summary>
/// Guid for a Member Type object.
/// </summary>
public const string MemberType = "9B5416FB-E72F-45A9-A07B-5A9A2709CE43";
/// <summary>
/// Guid for a Stylesheet object.
/// </summary>
/// <summary>
/// Guid for a Stylesheet object.
/// </summary>
[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";
/// <summary>
/// Guid for the System Root.
/// </summary>
public const string SystemRoot = "EA7D8624-4CFE-4578-A871-24AA946BF34D";
/// <summary>
/// Guid for the System Root.
/// </summary>
public const string SystemRoot = "EA7D8624-4CFE-4578-A871-24AA946BF34D";
/// <summary>
/// Guid for a Template object.
/// </summary>
public const string Template = "6FBDE604-4178-42CE-A10B-8A2600A2F07D";
}
}
/// <summary>
/// Guid for a Template object.
/// </summary>
public const string Template = "6FBDE604-4178-42CE-A10B-8A2600A2F07D";
/// <summary>
/// Guid for a Lock object.
/// </summary>
public const string LockObject = "87A9F1FF-B1E4-4A25-BABB-465A4A47EC41";
}
}
}
+2
View File
@@ -26,6 +26,8 @@
public const int DefaultMediaListViewDataTypeId = -96;
public const int DefaultMembersListViewDataTypeId = -97;
// identifiers for lock objects
public const int ServersLock = -331;
}
}
}
+44
View File
@@ -0,0 +1,44 @@
using System;
using System.Diagnostics;
using System.Threading;
namespace Umbraco.Core
{
public static class DelegateExtensions
{
public static Attempt<T> RetryUntilSuccessOrTimeout<T>(this Func<Attempt<T>> 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<T>.Fail();
}
public static Attempt<T> RetryUntilSuccessOrMaxAttempts<T>(this Func<int, Attempt<T>> 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<T>.Fail();
}
}
}
+33 -15
View File
@@ -152,12 +152,7 @@ namespace Umbraco.Core.IO
/// <returns>A value indicating whether the filepath is valid.</returns>
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 });
}
/// <summary>
@@ -182,15 +177,31 @@ namespace Umbraco.Core.IO
/// <returns>A value indicating whether the filepath is valid.</returns>
internal static bool VerifyEditPath(string filePath, IEnumerable<string> 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
/// <returns>A value indicating whether the filepath is valid.</returns>
internal static bool VerifyFileExtension(string filePath, List<string> 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('.'));
}
/// <summary>
@@ -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;
}
/// <summary>
/// Returns the path to the root of the application, by getting the path to where the assembly where this
+124 -44
View File
@@ -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<string> 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<string> 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!
/// <summary>
/// Gets the relative path.
/// </summary>
/// <param name="fullPathOrUrl">The full path or url.</param>
/// <returns>The path, relative to this filesystem's root.</returns>
/// <remarks>
/// <para>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.</para>
/// </remarks>
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;
}
/// <summary>
/// Gets the full path.
/// </summary>
/// <param name="path">The full or relative path.</param>
/// <returns>The full path.</returns>
/// <remarks>
/// <para>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.</para>
/// </remarks>
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;
}
@@ -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;
+16 -4
View File
@@ -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<PackageManifest>();
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<ManifestParser>("An error occurred parsing manifest with contents: " + m, ex);
LogHelper.Error<ManifestParser>("An error occurred parsing manifest with contents: " + manifestContent, ex);
continue;
}
+57 -13
View File
@@ -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<File, string> GetFileContent { get; set; }
protected File(string path, Func<File, string> getFileContent = null)
{
_path = path;
_path = SanitizePath(path);
_originalPath = _path;
GetFileContent = getFileContent;
_content = getFileContent != null ? null : string.Empty;
}
private static readonly PropertyInfo ContentSelector = ExpressionHelper.GetPropertyInfo<File, string>(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);
}
/// <summary>
/// Gets or sets the Name of the File including extension
/// </summary>
@@ -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
/// <summary>
/// Gets or sets the Content of a File
/// </summary>
/// <remarks>Marked as DoNotClone, because it should be lazy-reloaded from disk.</remarks>
[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;
@@ -0,0 +1,14 @@
using System;
namespace Umbraco.Core.Models
{
/// <summary>
/// Represents a cached content with a GUID key.
/// </summary>
/// <remarks>This is temporary, because we cannot add the Key property to IPublishedContent without
/// breaking backward compatibility. With v8, it will be merged into IPublishedContent.</remarks>
public interface IPublishedContentWithKey : IPublishedContent
{
Guid Key { get; }
}
}
@@ -18,6 +18,11 @@ namespace Umbraco.Core.Models
/// </summary>
bool IsActive { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the server is master.
/// </summary>
bool IsMaster { get; set; }
/// <summary>
/// Gets the date and time the registration was created.
/// </summary>
+8 -9
View File
@@ -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<File, string> getFileContent)
: base(path, getFileContent)
{ }
internal PartialViewType ViewType { get; set; }
}
}
@@ -0,0 +1,9 @@
namespace Umbraco.Core.Models
{
internal enum PartialViewType : byte
{
Unknown = 0, // default
PartialView = 1,
PartialViewMacro = 2
}
}
@@ -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
@@ -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; } }
}
}
@@ -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; } }
}
}
@@ -0,0 +1,17 @@
using System;
namespace Umbraco.Core.Models.PublishedContent
{
/// <summary>
/// Provides an abstract base class for <c>IPublishedContentWithKey</c> implementations that
/// wrap and extend another <c>IPublishedContentWithKey</c>.
/// </summary>
public class PublishedContentWithKeyWrapped : PublishedContentWrapped, IPublishedContentWithKey
{
protected PublishedContentWithKeyWrapped(IPublishedContentWithKey content)
: base(content)
{ }
public virtual Guid Key { get { return ((IPublishedContentWithKey) Content).Key; } }
}
}
+3 -2
View File
@@ -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]
@@ -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; }
}
}
@@ -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]
+2 -1
View File
@@ -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")]
@@ -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; }
+2 -1
View File
@@ -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")]
@@ -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")]
+3 -2
View File
@@ -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; }
}
}
@@ -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; }
}
+2 -1
View File
@@ -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")]
@@ -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; }
}
}
+2 -1
View File
@@ -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")]
+8 -9
View File
@@ -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<File, string>) null)
{ }
internal Script(string path, Func<File, string> 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)
{ }
/// <summary>
/// Indicates whether the current entity has an identity, which in this case is a path/name.
+22 -3
View File
@@ -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<ServerRegistration, string>(x => x.ServerAddress);
private static readonly PropertyInfo ServerIdentitySelector = ExpressionHelper.GetPropertyInfo<ServerRegistration, string>(x => x.ServerIdentity);
private static readonly PropertyInfo IsActiveSelector = ExpressionHelper.GetPropertyInfo<ServerRegistration, bool>(x => x.IsActive);
private static readonly PropertyInfo IsMasterSelector = ExpressionHelper.GetPropertyInfo<ServerRegistration, bool>(x => x.IsMaster);
/// <summary>
/// Initialiazes a new instance of the <see cref="ServerRegistration"/> class.
@@ -34,7 +35,8 @@ namespace Umbraco.Core.Models
/// <param name="registered">The date and time the registration was created.</param>
/// <param name="accessed">The date and time the registration was last accessed.</param>
/// <param name="isActive">A value indicating whether the registration is active.</param>
public ServerRegistration(int id, string serverAddress, string serverIdentity, DateTime registered, DateTime accessed, bool isActive)
/// <param name="isMaster">A value indicating whether the registration is master.</param>
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;
}
/// <summary>
@@ -108,6 +111,22 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Gets or sets a value indicating whether the server is master.
/// </summary>
public bool IsMaster
{
get { return _isMaster; }
set
{
SetPropertyValueAndDetectChanges(o =>
{
_isMaster = value;
return _isMaster;
}, _isMaster, IsMasterSelector);
}
}
/// <summary>
/// Gets the date and time the registration was created.
/// </summary>
@@ -124,7 +143,7 @@ namespace Umbraco.Core.Models
/// <returns></returns>
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 ? "" : "!");
}
}
}
+10 -6
View File
@@ -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<File, string> getFileContent)
: base(path.EnsureEndsWith(".css"), getFileContent)
{
InitializeProperties();
}
private Lazy<List<StylesheetProperty>> _properties;
private void InitializeProperties()
@@ -81,7 +85,7 @@ namespace Umbraco.Core.Models
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void Property_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
void Property_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
var prop = (StylesheetProperty) sender;
+11 -23
View File
@@ -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<Template, string>(x => x.Name);
public Template(string name, string alias)
: base(string.Empty)
: this(name, alias, (Func<File, string>) null)
{ }
internal Template(string name, string alias, Func<File, string> getFileContent)
: base(string.Empty, getFileContent)
{
_name = name;
_alias = alias.ToCleanString(CleanStringType.UnderscoreAlias);
_masterTemplateId = new Lazy<int>(() => -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
}
}
}
@@ -20,6 +20,6 @@ namespace Umbraco.Core.Persistence.DatabaseAnnotations
/// <summary>
/// Gets or sets the Default value
/// </summary>
public string Default { get; set; }
public object Default { get; set; }
}
}
@@ -3,8 +3,8 @@ namespace Umbraco.Core.Persistence.DatabaseModelDefinitions
public enum SystemMethods
{
NewGuid,
NewSequentialId,
CurrentDateTime,
CurrentUTCDateTime
//NewSequentialId,
//CurrentUTCDateTime
}
}
@@ -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<int>("SELECT sortOrder FROM umbracoNode WHERE id=@id",
new { @id = nodeId });
}
}
}
@@ -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
};
@@ -33,9 +33,9 @@ namespace Umbraco.Core.Persistence.Factories
#region Implementation of IEntityFactory<ITemplate,TemplateDto>
public Template BuildEntity(TemplateDto dto, IEnumerable<IUmbracoEntity> childDefinitions)
public Template BuildEntity(TemplateDto dto, IEnumerable<IUmbracoEntity> childDefinitions, Func<File, string> 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,
@@ -0,0 +1,27 @@
using System;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Persistence
{
internal class LockedRepository<TRepository>
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();
}
}
}
@@ -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<TRepository>
where TRepository : IDisposable, IRepository
{
private readonly IDatabaseUnitOfWorkProvider _uowProvider;
private readonly Func<IDatabaseUnitOfWork, TRepository> _repositoryFactory;
private readonly int[] _readLockIds, _writeLockIds;
public LockingRepository(IDatabaseUnitOfWorkProvider uowProvider, Func<IDatabaseUnitOfWork, TRepository> repositoryFactory,
IEnumerable<int> readLockIds, IEnumerable<int> 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<LockedRepository<TRepository>> 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<TRepository>(transaction, uow, repository));
if (autoCommit == false) return;
uow.Commit();
transaction.Complete();
}
}
}
public TResult WithReadLocked<TResult>(Func<LockedRepository<TRepository>, 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<TRepository>(transaction, uow, repository));
if (autoCommit == false) return ret;
uow.Commit();
transaction.Complete();
return ret;
}
}
}
public void WithWriteLocked(Action<LockedRepository<TRepository>> 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<TRepository>(transaction, uow, repository));
if (autoCommit == false) return;
uow.Commit();
transaction.Complete();
}
}
}
public TResult WithWriteLocked<TResult>(Func<LockedRepository<TRepository>, 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<TRepository>(transaction, uow, repository));
if (autoCommit == false) return ret;
uow.Commit();
transaction.Complete();
return ret;
}
}
}
}
}
@@ -30,6 +30,7 @@ namespace Umbraco.Core.Persistence.Mappers
{
CacheMap<ServerRegistration, ServerRegistrationDto>(src => src.Id, dto => dto.Id);
CacheMap<ServerRegistration, ServerRegistrationDto>(src => src.IsActive, dto => dto.IsActive);
CacheMap<ServerRegistration, ServerRegistrationDto>(src => src.IsMaster, dto => dto.IsMaster);
CacheMap<ServerRegistration, ServerRegistrationDto>(src => src.ServerAddress, dto => dto.ServerAddress);
CacheMap<ServerRegistration, ServerRegistrationDto>(src => src.CreateDate, dto => dto.DateRegistered);
CacheMap<ServerRegistration, ServerRegistrationDto>(src => src.UpdateDate, dto => dto.DateAccessed);
@@ -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);
}
}
}
@@ -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());
}
}
}
@@ -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<MigrationRunner>("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<MigrationRunner>("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<MigrationRunner>("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
@@ -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);
}
}
}
@@ -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);
@@ -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),
@@ -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));
}
}
}
@@ -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)
{
}
@@ -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;
@@ -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);
@@ -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);
@@ -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));
}
@@ -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<ColumnDefinition>();
}
//[Obsolete("Use the other constructors specifying an ISqlSyntaxProvider instead")]
//public CreateTableExpression()
//{
// Columns = new List<ColumnDefinition>();
//}
[Obsolete("Use the other constructors specifying an ISqlSyntaxProvider instead")]
public CreateTableExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders)
: base(current, databaseProviders)
{
Columns = new List<ColumnDefinition>();
}
//[Obsolete("Use the other constructors specifying an ISqlSyntaxProvider instead")]
//public CreateTableExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders)
// : base(current, databaseProviders)
//{
// Columns = new List<ColumnDefinition>();
//}
public CreateTableExpression(ISqlSyntaxProvider sqlSyntax)
: base(sqlSyntax)
{
Columns = new List<ColumnDefinition>();
}
//public CreateTableExpression(ISqlSyntaxProvider sqlSyntax)
// : base(sqlSyntax)
//{
// Columns = new List<ColumnDefinition>();
//}
public CreateTableExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
: base(current, databaseProviders, sqlSyntax)
@@ -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);
@@ -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);
}
@@ -7,13 +7,13 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
{
public class DeleteColumnExpression : MigrationExpressionBase
{
public DeleteColumnExpression()
{
ColumnNames = new List<string>();
}
//public DeleteColumnExpression()
//{
// ColumnNames = new List<string>();
//}
public DeleteColumnExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders)
: base(current, databaseProviders)
public DeleteColumnExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders, ISqlSyntaxProvider sqlSyntax)
: base(current, databaseProviders, sqlSyntax)
{
ColumnNames = new List<string>();
}
@@ -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();
@@ -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));
}
}
}
@@ -8,12 +8,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
public class DeleteDataExpression : MigrationExpressionBase
{
private readonly List<DeletionDataDefinition> _rows = new List<DeletionDataDefinition>();
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<string, object> 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())));
}
}
@@ -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);
}
@@ -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());
@@ -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));
}
}
}
@@ -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));
}
}
}
@@ -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();
@@ -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<Database, string> 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);
}
}
@@ -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)
{
}
@@ -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)
{
}
@@ -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));
}
}
}
@@ -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);
}
}
}
@@ -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()
{
@@ -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); }
}
}
}
@@ -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<InsertionDataDefinition> _rows = new List<InsertionDataDefinition>();
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<InsertionDataDefinition> 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<string>();
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();
}
@@ -2,6 +2,7 @@
{
public interface IInsertDataSyntax : IFluentSyntax
{
IInsertDataSyntax EnableIdentityInsert();
IInsertDataSyntax Row(object dataAsAnonymousType);
}
}
@@ -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);
}
@@ -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));
@@ -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);
}
}
}
@@ -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);
}
}
}
@@ -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);
}
@@ -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()));
}
@@ -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);
}
@@ -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<MacroDto>("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();
}
@@ -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")
@@ -55,9 +55,11 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven
}
var propertyTypeIds = propertyData.Select(x => x.PropertyTypeId).Distinct();
var propertyTypes = database.Fetch<PropertyTypeDto>(
"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<PropertyTypeDto>("SELECT * FROM cmsPropertyType WHERE id in (@propertyTypeIds)", new { propertyTypeIds = propertyTypeIds });
foreach (var data in propertyData)
{
if (string.IsNullOrEmpty(data.Text) == false)
@@ -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<LanguageDto>(new Sql().Select("*").From<LanguageDto>(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();
}
}
}
@@ -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<NodeDto>(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
});
}
}
}
@@ -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
{
/// <summary>
/// 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
/// </summary>
[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<DocumentDto>(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()
{
}
}
}
@@ -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()
@@ -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<dynamic>(new Sql().Select("*").From<TemplateDto>());
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<dynamic>("SELECT * FROM cmsTemplate");
foreach (var template in templateData)
{
var sql = "SET parentID=@parentId WHERE id=@nodeId";
LogHelper.Info<MigrateAndRemoveTemplateMasterColumn>("Executing sql statement: UPDATE umbracoNode " + sql);
database.Update<NodeDto>(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<dynamic>(new Sql().Select("*").From<TemplateDto>());
foreach (var template in templates)
{
var sql = string.Format(SqlSyntax.UpdateData,
SqlSyntax.GetQuotedTableName("umbracoNode"),
"path=@buildPath",
"id=@nodeId");
LogHelper.Info<MigrateAndRemoveTemplateMasterColumn>("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");
}
@@ -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<PropertyTypeDto>("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<PropertyTypeDto>("SELECT * FROM cmsPropertyType WHERE propertyTypeGroupId > 0");
var propertyGroups = database.Fetch<PropertyTypeGroupDto>("WHERE id > 0");
foreach (var propertyType in propertyTypes)
+79 -15
View File
@@ -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(@"(?<!@)@\w+", RegexOptions.Compiled);
public static string ProcessParams(string _sql, object[] args_src, List<object> 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();
}
@@ -654,8 +654,8 @@ namespace Umbraco.Core.Persistence.Repositories
var translator = new SqlTranslator<IContent>(sqlClause, query);
var sql = translator.Translate()
.Where<DocumentDto>(x => x.Published)
.OrderBy<NodeDto>(x => x.Level)
.OrderBy<NodeDto>(x => x.SortOrder);
.OrderBy<NodeDto>(x => x.Level, SqlSyntax)
.OrderBy<NodeDto>(x => x.SortOrder, SqlSyntax);
//NOTE: This doesn't allow properties to be part of the query
var dtos = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto, DocumentPublishedReadOnlyDto>(sql);
@@ -896,7 +896,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// <summary>
/// Private method to create a content object from a DocumentDto, which is used by Get and GetByVersion.
/// </summary>
/// <param name="d"></param>
/// <param name="dto"></param>
/// <param name="versionId"></param>
/// <param name="docSql"></param>
/// <returns></returns>
@@ -1130,6 +1130,11 @@ AND umbracoNode.id <> @id",
out IDictionary<int, PropertyTypeCollection> allPropertyTypeCollection,
out IDictionary<int, PropertyGroupCollection> allPropertyGroupCollection)
{
allPropertyGroupCollection = new Dictionary<int, PropertyGroupCollection>();
allPropertyTypeCollection = new Dictionary<int, PropertyTypeCollection>();
// 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<dynamic>(sqlBuilder.ToString(), new { contentTypeIds = contentTypeIds });
allPropertyGroupCollection = new Dictionary<int, PropertyGroupCollection>();
allPropertyTypeCollection = new Dictionary<int, PropertyTypeCollection>();
foreach (var contentTypeId in contentTypeIds)
{
//from this we need to make :
@@ -79,7 +79,7 @@ namespace Umbraco.Core.Persistence.Repositories
public object GetCacheItem(string cacheKey, Func<object> getCacheItem)
{
return InnerProvider.GetCacheItem(cacheKey, () =>
var cached = InnerProvider.GetCacheItem(cacheKey, () =>
{
var result = DictionaryCacheProviderBase.GetSafeLazy(getCacheItem);
var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache
@@ -87,18 +87,21 @@ namespace Umbraco.Core.Persistence.Repositories
return CheckCloneableAndTracksChanges(value);
});
return CheckCloneableAndTracksChanges(cached);
}
public object GetCacheItem(string cacheKey, Func<object> getCacheItem, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null)
{
return InnerProvider.GetCacheItem(cacheKey, () =>
var cached = InnerProvider.GetCacheItem(cacheKey, () =>
{
var result = DictionaryCacheProviderBase.GetSafeLazy(getCacheItem);
var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache
if (value == null) return null; // do not store null values (backward compat)
return CheckCloneableAndTracksChanges(value);
}, timeout, isSliding, priority, removedCallback, dependentFiles);
}, timeout, isSliding, priority, removedCallback, dependentFiles);
return CheckCloneableAndTracksChanges(cached);
}
public void InsertCacheItem(string cacheKey, Func<object> getCacheItem, TimeSpan? timeout = null, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null)
@@ -147,10 +147,6 @@ namespace Umbraco.Core.Persistence.Repositories
protected virtual void PersistUpdatedItem(TEntity entity)
{
//TODO: A big problem here is if the entities 'Path' changes, if that is the case then
// we'd need to rename the underlying file, BUT how would we do this since we aren't storing an
// original path property.
using (var stream = GetContentStream(entity.Content))
{
FileSystem.AddFile(entity.Path, stream, true);
@@ -219,6 +215,15 @@ namespace Umbraco.Core.Persistence.Repositories
return list;
}
protected string GetFileContent(string filename)
{
using (var stream = FileSystem.OpenFile(filename))
using (var reader = new StreamReader(stream, Encoding.UTF8, true))
{
return reader.ReadToEnd();
}
}
/// <summary>
/// Dispose any disposable properties
/// </summary>
@@ -6,5 +6,6 @@ namespace Umbraco.Core.Persistence.Repositories
{
void AddFolder(string folderPath);
void DeleteFolder(string folderPath);
bool ValidatePartialView(IPartialView partialView);
}
}

Some files were not shown because too many files have changed in this diff Show More