diff --git a/.gitignore b/.gitignore
index f644044430..bd7a0ffa9d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -141,5 +141,5 @@ build/docs.zip
build/ui-docs.zip
build/csharp-docs.zip
build/msbuild.log
-
+.vs/
src/packages/
\ No newline at end of file
diff --git a/src/Umbraco.Core/CoreBootManager.cs b/src/Umbraco.Core/CoreBootManager.cs
index 4da740f458..4ef08bd02f 100644
--- a/src/Umbraco.Core/CoreBootManager.cs
+++ b/src/Umbraco.Core/CoreBootManager.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Configuration;
using System.IO;
using System.Linq;
using System.Threading;
@@ -30,12 +31,13 @@ using Umbraco.Core.Manifest;
using Umbraco.Core.Services;
using Umbraco.Core.Sync;
using Umbraco.Core.Strings;
+using IntegerValidator = Umbraco.Core.PropertyEditors.IntegerValidator;
using MigrationsVersionFourNineZero = Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionFourNineZero;
namespace Umbraco.Core
{
///
- /// A bootstrapper for the Umbraco application which initializes all objects for the Core of the application
+ /// A bootstrapper for the Umbraco application which initializes all objects for the Core of the application
///
///
/// This does not provide any startup functionality relating to web objects
@@ -191,14 +193,14 @@ namespace Umbraco.Core
protected virtual CacheHelper CreateApplicationCache()
{
var cacheHelper = new CacheHelper(
- //we need to have the dep clone runtime cache provider to ensure
+ //we need to have the dep clone runtime cache provider to ensure
//all entities are cached properly (cloned in and cloned out)
new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()),
new StaticCacheProvider(),
//we have no request based cache when not running in web-based context
new NullCacheProvider(),
new IsolatedRuntimeCache(type =>
- //we need to have the dep clone runtime cache provider to ensure
+ //we need to have the dep clone runtime cache provider to ensure
//all entities are cached properly (cloned in and cloned out)
new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider())));
@@ -251,18 +253,18 @@ namespace Umbraco.Core
}
///
- /// Special method to initialize the ApplicationEventsResolver and any modifications required for it such
+ /// Special method to initialize the ApplicationEventsResolver and any modifications required for it such
/// as adding custom types to the resolver.
///
protected virtual void InitializeApplicationEventsResolver()
{
//find and initialize the application startup handlers, we need to initialize this resolver here because
- //it is a special resolver where they need to be instantiated first before any other resolvers in order to bind to
+ //it is a special resolver where they need to be instantiated first before any other resolvers in order to bind to
//events and to call their events during bootup.
//ApplicationStartupHandler.RegisterHandlers();
//... and set the special flag to let us resolve before frozen resolution
ApplicationEventsResolver.Current = new ApplicationEventsResolver(
- ServiceProvider,
+ ServiceProvider,
ProfilingLogger.Logger,
PluginManager.ResolveApplicationStartupHandlers())
{
@@ -282,7 +284,7 @@ namespace Umbraco.Core
}
///
- /// Fires after initialization and calls the callback to allow for customizations to occur &
+ /// Fires after initialization and calls the callback to allow for customizations to occur &
/// Ensure that the OnApplicationStarting methods of the IApplicationEvents are called
///
///
@@ -334,7 +336,7 @@ namespace Umbraco.Core
{
if (_isComplete)
throw new InvalidOperationException("The boot manager has already been completed");
-
+
FreezeResolution();
//Here we need to make sure the db can be connected to
@@ -366,7 +368,7 @@ namespace Umbraco.Core
ProfilingLogger.Logger.Error("An error occurred running OnApplicationStarted for handler " + x.GetType(), ex);
throw;
}
- });
+ });
}
//Now, startup all of our legacy startup handler
@@ -455,6 +457,10 @@ namespace Umbraco.Core
{
ServerRegistrarResolver.Current = new ServerRegistrarResolver(new ConfigServerRegistrar());
}
+ else if ("true".InvariantEquals(ConfigurationManager.AppSettings["umbracoDisableElectionForSingleServer"]))
+ {
+ ServerRegistrarResolver.Current = new ServerRegistrarResolver(new SingleServerRegistrar());
+ }
else
{
ServerRegistrarResolver.Current = new ServerRegistrarResolver(
@@ -462,7 +468,6 @@ namespace Umbraco.Core
new Lazy(() => ApplicationContext.Services.ServerRegistrationService),
new DatabaseServerRegistrarOptions()));
}
-
//by default we'll use the database server messenger with default options (no callbacks),
// this will be overridden in the web startup
@@ -473,7 +478,7 @@ namespace Umbraco.Core
ServiceProvider, ProfilingLogger.Logger,
() => PluginManager.ResolveAssignedMapperTypes());
-
+
//RepositoryResolver.Current = new RepositoryResolver(
// new RepositoryFactory(ApplicationCache));
diff --git a/src/Umbraco.Core/Models/Rdbms/PropertyDataDto.cs b/src/Umbraco.Core/Models/Rdbms/PropertyDataDto.cs
index c4cd28f6e0..e9c1685bb3 100644
--- a/src/Umbraco.Core/Models/Rdbms/PropertyDataDto.cs
+++ b/src/Umbraco.Core/Models/Rdbms/PropertyDataDto.cs
@@ -11,7 +11,6 @@ namespace Umbraco.Core.Models.Rdbms
{
[Column("id")]
[PrimaryKeyColumn]
- [Index(IndexTypes.NonClustered, Name = "IX_cmsPropertyData")]
public int Id { get; set; }
[Column("contentNodeId")]
diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenSixZero/RemovePropertyDataIdIndex.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenSixZero/RemovePropertyDataIdIndex.cs
new file mode 100644
index 0000000000..b50c8e5f94
--- /dev/null
+++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenSixZero/RemovePropertyDataIdIndex.cs
@@ -0,0 +1,38 @@
+using System.Linq;
+using Umbraco.Core.Configuration;
+using Umbraco.Core.Logging;
+using Umbraco.Core.Persistence.SqlSyntax;
+
+namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
+{
+ ///
+ /// See: http://issues.umbraco.org/issue/U4-9188
+ ///
+ [Migration("7.6.0", 0, GlobalSettings.UmbracoMigrationName)]
+ public class UpdateUniqueIndexOnCmsPropertyData : MigrationBase
+ {
+ public UpdateUniqueIndexOnCmsPropertyData(ISqlSyntaxProvider sqlSyntax, ILogger logger)
+ : base(sqlSyntax, logger)
+ {
+ }
+
+ public override void Up()
+ {
+ //tuple = tablename, indexname, columnname, unique
+ var indexes = SqlSyntax.GetDefinedIndexes(Context.Database).ToArray();
+ var found = indexes.FirstOrDefault(
+ x => x.Item1.InvariantEquals("cmsPropertyData")
+ && x.Item2.InvariantEquals("IX_cmsPropertyData"));
+
+ if (found != null)
+ {
+ //drop the index
+ Delete.Index("IX_cmsPropertyData").OnTable("cmsPropertyData");
+ }
+ }
+
+ public override void Down()
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/PetaPoco.cs b/src/Umbraco.Core/Persistence/PetaPoco.cs
index 63278889a2..88ff456ff6 100644
--- a/src/Umbraco.Core/Persistence/PetaPoco.cs
+++ b/src/Umbraco.Core/Persistence/PetaPoco.cs
@@ -739,6 +739,11 @@ namespace Umbraco.Core.Persistence
///
internal virtual void BuildSqlDbSpecificPagingQuery(DBType databaseType, long skip, long take, string sql, string sqlSelectRemoved, string sqlOrderBy, ref object[] args, out string sqlPage)
{
+ // this is overriden in UmbracoDatabase, and if running SqlServer >=2012, the database type
+ // is switched from SqlServer to SqlServerCE in order to use the better paging syntax that
+ // SqlCE supports, and SqlServer >=2012 too.
+ // so the first case is actually for SqlServer <2012, and second case is CE *and* SqlServer >=2012
+
if (databaseType == DBType.SqlServer || databaseType == DBType.Oracle)
{
sqlSelectRemoved = rxOrderBy.Replace(sqlSelectRemoved, "");
@@ -746,8 +751,16 @@ namespace Umbraco.Core.Persistence
{
sqlSelectRemoved = "peta_inner.* FROM (SELECT " + sqlSelectRemoved + ") peta_inner";
}
- sqlPage = string.Format("SELECT * FROM (SELECT ROW_NUMBER() OVER ({0}) peta_rn, {1}) peta_paged WHERE peta_rn>@{2} AND peta_rn<=@{3}",
- sqlOrderBy == null ? "ORDER BY (SELECT NULL)" : sqlOrderBy, sqlSelectRemoved, args.Length, args.Length + 1);
+
+ // split to ensure that peta_rn is the last field to be selected, else Page would fail
+ // the resulting sql is not perfect, NPoco has a much nicer way to do it, but it would require
+ // importing large parts of NPoco
+ var pos = sqlSelectRemoved.IndexOf("FROM");
+ var sqlColumns = sqlSelectRemoved.Substring(0, pos);
+ var sqlFrom = sqlSelectRemoved.Substring(pos);
+
+ sqlPage = string.Format("SELECT * FROM (SELECT {0}, ROW_NUMBER() OVER ({1}) peta_rn {2}) peta_paged WHERE peta_rn>@{3} AND peta_rn<=@{4}",
+ sqlColumns, sqlOrderBy ?? "ORDER BY (SELECT NULL)", sqlFrom, args.Length, args.Length + 1);
args = args.Concat(new object[] { skip, skip + take }).ToArray();
}
else if (databaseType == DBType.SqlServerCE)
@@ -774,7 +787,7 @@ namespace Umbraco.Core.Persistence
throw new Exception("Unable to parse SQL statement for paged query");
if (_dbType == DBType.Oracle && sqlSelectRemoved.StartsWith("*"))
throw new Exception("Query must alias '*' when performing a paged query.\neg. select t.* from table t order by t.id");
-
+
BuildSqlDbSpecificPagingQuery(_dbType, skip, take, sql, sqlSelectRemoved, sqlOrderBy, ref args, out sqlPage);
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
index c4b1884f17..9f9180c98f 100644
--- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
@@ -1,22 +1,14 @@
using System;
using System.Collections.Generic;
-using System.Data;
using System.Globalization;
using System.Linq;
-using System.Linq.Expressions;
-using System.Net.Http.Headers;
-using System.Text;
using System.Xml;
using System.Xml.Linq;
-using Umbraco.Core.Configuration;
-using Umbraco.Core.Dynamics;
-using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Models.Rdbms;
-
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
@@ -81,7 +73,7 @@ namespace Umbraco.Core.Persistence.Repositories
var sql = GetBaseQuery(false);
if (ids.Any())
{
- sql.Where("umbracoNode.id in (@ids)", new { ids = ids });
+ sql.Where("umbracoNode.id in (@ids)", new { ids });
}
//we only want the newest ones with this method
@@ -224,6 +216,14 @@ namespace Umbraco.Core.Persistence.Repositories
}
}
+ public override IEnumerable GetAllVersions(int id)
+ {
+ var sql = GetBaseQuery(false)
+ .Where(GetBaseWhereClause(), new { Id = id })
+ .OrderByDescending(x => x.VersionDate, SqlSyntax);
+ return ProcessQuery(sql, true);
+ }
+
public override IContent GetByVersion(Guid versionId)
{
var sql = GetBaseQuery(false);
@@ -633,29 +633,9 @@ namespace Umbraco.Core.Persistence.Repositories
.OrderBy(x => x.Level, SqlSyntax)
.OrderBy(x => x.SortOrder, SqlSyntax);
- //NOTE: This doesn't allow properties to be part of the query
- var dtos = Database.Fetch(sql);
-
- foreach (var dto in dtos)
- {
- //Check in the cache first. If it exists there AND it is published
- // then we can use that entity. Otherwise if it is not published (which can be the case
- // because we only store the 'latest' entries in the cache which might not be the published
- // version)
- var fromCache = RuntimeCache.GetCacheItem(GetCacheIdKey(dto.NodeId));
- //var fromCache = TryGetFromCache(dto.NodeId);
- if (fromCache != null && fromCache.Published)
- {
- yield return fromCache;
- }
- else
- {
- yield return CreateContentFromDto(dto, dto.VersionId, sql);
- }
- }
+ return ProcessQuery(sql, true);
}
-
///
/// This builds the Xml document used for the XML cache
///
@@ -829,7 +809,7 @@ order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder";
return GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords,
new Tuple("cmsDocument", "nodeId"),
- ProcessQuery, orderBy, orderDirection, orderBySystemField,
+ sql => ProcessQuery(sql), orderBy, orderDirection, orderBySystemField,
filterCallback);
}
@@ -860,83 +840,79 @@ order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder";
return base.GetDatabaseFieldNameForOrderBy(orderBy);
}
- private IEnumerable ProcessQuery(Sql sql)
+ private IEnumerable ProcessQuery(Sql sql, bool withCache = false)
{
- //NOTE: This doesn't allow properties to be part of the query
+ // fetch returns a list so it's ok to iterate it in this method
var dtos = Database.Fetch(sql);
+ if (dtos.Count == 0) return Enumerable.Empty();
- //nothing found
- if (dtos.Any() == false) return Enumerable.Empty();
+ var content = new IContent[dtos.Count];
+ var defs = new List();
+ var templateIds = new List();
- //content types
- //NOTE: This should be ok for an SQL 'IN' statement, there shouldn't be an insane amount of content types
- var contentTypes = _contentTypeRepository.GetAll(dtos.Select(x => x.ContentVersionDto.ContentDto.ContentTypeId).ToArray())
- .ToArray();
-
-
- var ids = dtos
- .Where(dto => dto.TemplateId.HasValue && dto.TemplateId.Value > 0)
- .Select(x => x.TemplateId.Value).ToArray();
-
- //NOTE: This should be ok for an SQL 'IN' statement, there shouldn't be an insane amount of content types
- var templates = ids.Length == 0 ? Enumerable.Empty() : _templateRepository.GetAll(ids).ToArray();
-
- var dtosWithContentTypes = dtos
- //This select into and null check are required because we don't have a foreign damn key on the contentType column
- // http://issues.umbraco.org/issue/U4-5503
- .Select(x => new { dto = x, contentType = contentTypes.FirstOrDefault(ct => ct.Id == x.ContentVersionDto.ContentDto.ContentTypeId) })
- .Where(x => x.contentType != null)
- .ToArray();
-
- //Go get the property data for each document
- var docDefs = dtosWithContentTypes.Select(d => new DocumentDefinition(
- d.dto.NodeId,
- d.dto.VersionId,
- d.dto.ContentVersionDto.VersionDate,
- d.dto.ContentVersionDto.ContentDto.NodeDto.CreateDate,
- d.contentType));
-
- var propertyData = GetPropertyCollection(sql, docDefs);
-
- return dtosWithContentTypes.Select(d => CreateContentFromDto(
- d.dto,
- contentTypes.First(ct => ct.Id == d.dto.ContentVersionDto.ContentDto.ContentTypeId),
- templates.FirstOrDefault(tem => tem.Id == (d.dto.TemplateId.HasValue ? d.dto.TemplateId.Value : -1)),
- propertyData[d.dto.NodeId]));
- }
-
- ///
- /// Private method to create a content object from a DocumentDto, which is used by Get and GetByVersion.
- ///
- ///
- ///
- ///
- ///
- ///
- private IContent CreateContentFromDto(DocumentDto dto,
- IContentType contentType,
- ITemplate template,
- Models.PropertyCollection propCollection)
- {
- var factory = new ContentFactory(contentType, NodeObjectTypeId, dto.NodeId);
- var content = factory.BuildEntity(dto);
-
- //Check if template id is set on DocumentDto, and get ITemplate if it is.
- if (dto.TemplateId.HasValue && dto.TemplateId.Value > 0)
+ for (var i = 0; i < dtos.Count; i++)
{
- content.Template = template ?? _templateRepository.Get(dto.TemplateId.Value);
- }
- else
- {
- //ensure there isn't one set.
- content.Template = null;
+ var dto = dtos[i];
+
+ // if the cache contains the published version, use it
+ if (withCache)
+ {
+ var cached = RuntimeCache.GetCacheItem(GetCacheIdKey(dto.NodeId));
+ if (cached != null && cached.Published)
+ {
+ content[i] = cached;
+ continue;
+ }
+ }
+
+ // else, need to fetch from the database
+ // content type repository is full-cache so OK to get each one independently
+ var contentType = _contentTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
+ var factory = new ContentFactory(contentType, NodeObjectTypeId, dto.NodeId);
+ content[i] = factory.BuildEntity(dto);
+
+ // need template
+ if (dto.TemplateId.HasValue && dto.TemplateId.Value > 0)
+ templateIds.Add(dto.TemplateId.Value);
+
+ // need properties
+ defs.Add(new DocumentDefinition(
+ dto.NodeId,
+ dto.VersionId,
+ dto.ContentVersionDto.VersionDate,
+ dto.ContentVersionDto.ContentDto.NodeDto.CreateDate,
+ contentType
+ ));
}
- content.Properties = propCollection;
+ // load all required templates in 1 query
+ var templates = _templateRepository.GetAll(templateIds.ToArray())
+ .ToDictionary(x => x.Id, x => x);
+
+ // load all properties for all documents from database in 1 query
+ var propertyData = GetPropertyCollection(sql, defs);
+
+ // assign
+ var dtoIndex = 0;
+ foreach (var def in defs)
+ {
+ // move to corresponding item (which has to exist)
+ while (dtos[dtoIndex].NodeId != def.Id) dtoIndex++;
+
+ // complete the item
+ var cc = content[dtoIndex];
+ var dto = dtos[dtoIndex];
+ ITemplate template = null;
+ if (dto.TemplateId.HasValue)
+ templates.TryGetValue(dto.TemplateId.Value, out template); // else null
+ cc.Template = template;
+ cc.Properties = propertyData[cc.Id];
+
+ //on initial construction we don't want to have dirty properties tracked
+ // http://issues.umbraco.org/issue/U4-1946
+ ((Entity) cc).ResetDirtyProperties(false);
+ }
- //on initial construction we don't want to have dirty properties tracked
- // http://issues.umbraco.org/issue/U4-1946
- ((Entity)content).ResetDirtyProperties(false);
return content;
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs
index 38e5e46cde..092b7df025 100644
--- a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs
@@ -4,21 +4,17 @@ using System.Globalization;
using System.Linq;
using System.Text;
using System.Xml.Linq;
-using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
-using Umbraco.Core.Dynamics;
-using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
-
+using Umbraco.Core.Cache;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
-using Umbraco.Core.Services;
namespace Umbraco.Core.Persistence.Repositories
{
@@ -137,6 +133,74 @@ namespace Umbraco.Core.Persistence.Repositories
#region Overrides of VersionableRepositoryBase
+ public override IEnumerable GetAllVersions(int id)
+ {
+ var sql = GetBaseQuery(false)
+ .Where(GetBaseWhereClause(), new { Id = id })
+ .OrderByDescending(x => x.VersionDate, SqlSyntax);
+ return ProcessQuery(sql, true);
+ }
+
+ private IEnumerable ProcessQuery(Sql sql, bool withCache = false)
+ {
+ // fetch returns a list so it's ok to iterate it in this method
+ var dtos = Database.Fetch(sql);
+ var content = new IMedia[dtos.Count];
+ var defs = new List();
+
+ for (var i = 0; i < dtos.Count; i++)
+ {
+ var dto = dtos[i];
+
+ // if the cache contains the item, use it
+ if (withCache)
+ {
+ var cached = RuntimeCache.GetCacheItem(GetCacheIdKey(dto.NodeId));
+ if (cached != null)
+ {
+ content[i] = cached;
+ continue;
+ }
+ }
+
+ // else, need to fetch from the database
+ // content type repository is full-cache so OK to get each one independently
+ var contentType = _mediaTypeRepository.Get(dto.ContentDto.ContentTypeId);
+ var factory = new MediaFactory(contentType, NodeObjectTypeId, dto.NodeId);
+ content[i] = factory.BuildEntity(dto);
+
+ // need properties
+ defs.Add(new DocumentDefinition(
+ dto.NodeId,
+ dto.VersionId,
+ dto.VersionDate,
+ dto.ContentDto.NodeDto.CreateDate,
+ contentType
+ ));
+ }
+
+ // load all properties for all documents from database in 1 query
+ var propertyData = GetPropertyCollection(sql, defs);
+
+ // assign
+ var dtoIndex = 0;
+ foreach (var def in defs)
+ {
+ // move to corresponding item (which has to exist)
+ while (dtos[dtoIndex].NodeId != def.Id) dtoIndex++;
+
+ // complete the item
+ var cc = content[dtoIndex];
+ cc.Properties = propertyData[cc.Id];
+
+ //on initial construction we don't want to have dirty properties tracked
+ // http://issues.umbraco.org/issue/U4-1946
+ ((Entity) cc).ResetDirtyProperties(false);
+ }
+
+ return content;
+ }
+
public override IMedia GetByVersion(Guid versionId)
{
var sql = GetBaseQuery(false);
@@ -431,7 +495,7 @@ namespace Umbraco.Core.Persistence.Repositories
return GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords,
new Tuple("cmsContentVersion", "contentId"),
- ProcessQuery, orderBy, orderDirection, orderBySystemField,
+ sql => ProcessQuery(sql), orderBy, orderDirection, orderBySystemField,
filterCallback);
}
@@ -460,62 +524,6 @@ namespace Umbraco.Core.Persistence.Repositories
return pagedResult.Items.Select(dto => XElement.Parse(dto.Xml));
}
- private IEnumerable ProcessQuery(Sql sql)
- {
- //NOTE: This doesn't allow properties to be part of the query
- var dtos = Database.Fetch(sql);
-
- var ids = dtos.Select(x => x.ContentDto.ContentTypeId).ToArray();
-
- //content types
- var contentTypes = ids.Length == 0 ? Enumerable.Empty() : _mediaTypeRepository.GetAll(ids).ToArray();
-
- var dtosWithContentTypes = dtos
- //This select into and null check are required because we don't have a foreign damn key on the contentType column
- // http://issues.umbraco.org/issue/U4-5503
- .Select(x => new { dto = x, contentType = contentTypes.FirstOrDefault(ct => ct.Id == x.ContentDto.ContentTypeId) })
- .Where(x => x.contentType != null)
- .ToArray();
-
- //Go get the property data for each document
- var docDefs = dtosWithContentTypes.Select(d => new DocumentDefinition(
- d.dto.NodeId,
- d.dto.VersionId,
- d.dto.VersionDate,
- d.dto.ContentDto.NodeDto.CreateDate,
- d.contentType))
- .ToArray();
-
- var propertyData = GetPropertyCollection(sql, docDefs);
-
- return dtosWithContentTypes.Select(d => CreateMediaFromDto(
- d.dto,
- contentTypes.First(ct => ct.Id == d.dto.ContentDto.ContentTypeId),
- propertyData[d.dto.NodeId]));
- }
-
- ///
- /// Private method to create a media object from a ContentDto
- ///
- ///
- ///
- ///
- ///
- private IMedia CreateMediaFromDto(ContentVersionDto dto,
- IMediaType contentType,
- PropertyCollection propCollection)
- {
- var factory = new MediaFactory(contentType, NodeObjectTypeId, dto.NodeId);
- var media = factory.BuildEntity(dto);
-
- media.Properties = propCollection;
-
- //on initial construction we don't want to have dirty properties tracked
- // http://issues.umbraco.org/issue/U4-1946
- ((Entity)media).ResetDirtyProperties(false);
- return media;
- }
-
///
/// Private method to create a media object from a ContentDto
///
diff --git a/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs
index 66f803f9cd..dcab898685 100644
--- a/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs
@@ -2,24 +2,19 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
-using System.Linq.Expressions;
using System.Text;
using System.Xml.Linq;
-using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
-using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
-
+using Umbraco.Core.Cache;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
-using Umbraco.Core.Persistence.Relators;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
-using Umbraco.Core.Dynamics;
namespace Umbraco.Core.Persistence.Repositories
{
@@ -380,6 +375,14 @@ namespace Umbraco.Core.Persistence.Repositories
#region Overrides of VersionableRepositoryBase
+ public override IEnumerable GetAllVersions(int id)
+ {
+ var sql = GetBaseQuery(false)
+ .Where(GetBaseWhereClause(), new { Id = id })
+ .OrderByDescending(x => x.VersionDate, SqlSyntax);
+ return ProcessQuery(sql, true);
+ }
+
public void RebuildXmlStructures(Func serializer, int groupSize = 200, IEnumerable contentTypeIds = null)
{
// the previous way of doing this was to run it all in one big transaction,
@@ -616,7 +619,7 @@ namespace Umbraco.Core.Persistence.Repositories
return GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords,
new Tuple("cmsMember", "nodeId"),
- ProcessQuery, orderBy, orderDirection, orderBySystemField,
+ sql => ProcessQuery(sql), orderBy, orderDirection, orderBySystemField,
filterCallback);
}
@@ -656,59 +659,65 @@ namespace Umbraco.Core.Persistence.Repositories
return base.GetEntityPropertyNameForOrderBy(orderBy);
}
- private IEnumerable ProcessQuery(Sql sql)
+ private IEnumerable ProcessQuery(Sql sql, bool withCache = false)
{
- //NOTE: This doesn't allow properties to be part of the query
+ // fetch returns a list so it's ok to iterate it in this method
var dtos = Database.Fetch(sql);
- var ids = dtos.Select(x => x.ContentVersionDto.ContentDto.ContentTypeId).ToArray();
+ var content = new IMember[dtos.Count];
+ var defs = new List();
- //content types
- var contentTypes = ids.Length == 0 ? Enumerable.Empty() : _memberTypeRepository.GetAll(ids).ToArray();
+ for (var i = 0; i < dtos.Count; i++)
+ {
+ var dto = dtos[i];
- var dtosWithContentTypes = dtos
- //This select into and null check are required because we don't have a foreign damn key on the contentType column
- // http://issues.umbraco.org/issue/U4-5503
- .Select(x => new { dto = x, contentType = contentTypes.FirstOrDefault(ct => ct.Id == x.ContentVersionDto.ContentDto.ContentTypeId) })
- .Where(x => x.contentType != null)
- .ToArray();
+ // if the cache contains the item, use it
+ if (withCache)
+ {
+ var cached = RuntimeCache.GetCacheItem(GetCacheIdKey(dto.NodeId));
+ if (cached != null)
+ {
+ content[i] = cached;
+ continue;
+ }
+ }
- //Go get the property data for each document
- IEnumerable docDefs = dtosWithContentTypes.Select(d => new DocumentDefinition(
- d.dto.NodeId,
- d.dto.ContentVersionDto.VersionId,
- d.dto.ContentVersionDto.VersionDate,
- d.dto.ContentVersionDto.ContentDto.NodeDto.CreateDate,
- d.contentType));
+ // else, need to fetch from the database
+ // content type repository is full-cache so OK to get each one independently
+ var contentType = _memberTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
+ var factory = new MemberFactory(contentType, NodeObjectTypeId, dto.NodeId);
+ content[i] = factory.BuildEntity(dto);
- var propertyData = GetPropertyCollection(sql, docDefs);
+ // need properties
+ defs.Add(new DocumentDefinition(
+ dto.NodeId,
+ dto.ContentVersionDto.VersionId,
+ dto.ContentVersionDto.VersionDate,
+ dto.ContentVersionDto.ContentDto.NodeDto.CreateDate,
+ contentType
+ ));
+ }
- return dtosWithContentTypes.Select(d => CreateMemberFromDto(
- d.dto,
- contentTypes.First(ct => ct.Id == d.dto.ContentVersionDto.ContentDto.ContentTypeId),
- propertyData[d.dto.NodeId]));
- }
+ // load all properties for all documents from database in 1 query
+ var propertyData = GetPropertyCollection(sql, defs);
- ///
- /// Private method to create a member object from a MemberDto
- ///
- ///
- ///
- ///
- ///
- private IMember CreateMemberFromDto(MemberDto dto,
- IMemberType contentType,
- PropertyCollection propCollection)
- {
- var factory = new MemberFactory(contentType, NodeObjectTypeId, dto.ContentVersionDto.NodeId);
- var member = factory.BuildEntity(dto);
+ // assign
+ var dtoIndex = 0;
+ foreach (var def in defs)
+ {
+ // move to corresponding item (which has to exist)
+ while (dtos[dtoIndex].NodeId != def.Id) dtoIndex++;
- member.Properties = propCollection;
+ // complete the item
+ var cc = content[dtoIndex];
+ cc.Properties = propertyData[cc.Id];
- //on initial construction we don't want to have dirty properties tracked
- // http://issues.umbraco.org/issue/U4-1946
- ((Entity)member).ResetDirtyProperties(false);
- return member;
+ //on initial construction we don't want to have dirty properties tracked
+ // http://issues.umbraco.org/issue/U4-1946
+ ((Entity)cc).ResetDirtyProperties(false);
+ }
+
+ return content;
}
///
diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs
index 4c35c90e1b..6cc97bdfb3 100644
--- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs
+++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs
@@ -6,16 +6,11 @@ using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Persistence.SqlSyntax
{
///
- /// Represents an SqlSyntaxProvider for Sql Server
+ /// Represents an SqlSyntaxProvider for Sql Server.
///
- [SqlSyntaxProviderAttribute(Constants.DatabaseProviders.SqlServer)]
+ [SqlSyntaxProvider(Constants.DatabaseProviders.SqlServer)]
public class SqlServerSyntaxProvider : MicrosoftSqlSyntaxProviderBase
{
- public SqlServerSyntaxProvider()
- {
-
- }
-
///
/// Gets/sets the version of the current SQL server instance
///
@@ -31,7 +26,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
switch (firstPart)
{
case "13":
- _versionName = SqlServerVersionName.V2014;
+ _versionName = SqlServerVersionName.V2016;
break;
case "12":
_versionName = SqlServerVersionName.V2014;
@@ -75,7 +70,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
{
var items = db.Fetch("SELECT TableName = t.Name,ColumnName = c.Name,dc.Name,dc.[Definition] FROM sys.tables t INNER JOIN sys.default_constraints dc ON t.object_id = dc.parent_object_id INNER JOIN sys.columns c ON dc.parent_object_id = c.object_id AND c.column_id = dc.parent_column_id");
return items.Select(x => new Tuple(x.TableName, x.ColumnName, x.Name, x.Definition));
- }
+ }
public override IEnumerable GetTablesInSchema(Database db)
{
@@ -120,9 +115,9 @@ from sys.tables as T inner join sys.indexes as I on T.[object_id] = I.[object_id
inner join sys.all_columns as AC on IC.[object_id] = AC.[object_id] and IC.[column_id] = AC.[column_id]
WHERE I.name NOT LIKE 'PK_%'
order by T.name, I.name");
- return items.Select(item => new Tuple(item.TABLE_NAME, item.INDEX_NAME, item.COLUMN_NAME,
+ return items.Select(item => new Tuple(item.TABLE_NAME, item.INDEX_NAME, item.COLUMN_NAME,
item.UNIQUE == 1)).ToList();
-
+
}
public override bool DoesTableExist(Database db, string tableName)
@@ -164,7 +159,7 @@ order by T.name, I.name");
switch (systemMethod)
{
case SystemMethods.NewGuid:
- return "NEWID()";
+ return "NEWID()";
case SystemMethods.CurrentDateTime:
return "GETDATE()";
//case SystemMethods.NewSequentialId:
@@ -181,11 +176,11 @@ order by T.name, I.name");
get { return "ALTER TABLE [{0}] DROP CONSTRAINT [DF_{0}_{1}]"; }
}
-
+
public override string DropIndex { get { return "DROP INDEX {0} ON {1}"; } }
public override string RenameColumn { get { return "sp_rename '{0}.{1}', '{2}', 'COLUMN'"; } }
-
+
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Sync/ApplicationUrlHelper.cs b/src/Umbraco.Core/Sync/ApplicationUrlHelper.cs
index a417ec601a..7b713374aa 100644
--- a/src/Umbraco.Core/Sync/ApplicationUrlHelper.cs
+++ b/src/Umbraco.Core/Sync/ApplicationUrlHelper.cs
@@ -114,7 +114,8 @@ namespace Umbraco.Core.Sync
// - contain a scheme
// - end or not with a slash, it will be taken care of
// eg "http://www.mysite.com/umbraco"
- var registrar = ServerRegistrarResolver.Current.Registrar as IServerRegistrar2;
+ var resolver = ServerRegistrarResolver.HasCurrent ? ServerRegistrarResolver.Current : null;
+ var registrar = resolver == null ? null : resolver.Registrar as IServerRegistrar2;
url = registrar == null ? null : registrar.GetCurrentServerUmbracoApplicationUrl();
if (url.IsNullOrWhiteSpace() == false)
{
diff --git a/src/Umbraco.Core/Sync/SingleServerRegistrar.cs b/src/Umbraco.Core/Sync/SingleServerRegistrar.cs
new file mode 100644
index 0000000000..117ce516be
--- /dev/null
+++ b/src/Umbraco.Core/Sync/SingleServerRegistrar.cs
@@ -0,0 +1,37 @@
+using System.Collections.Generic;
+
+namespace Umbraco.Core.Sync
+{
+ public class SingleServerRegistrar : IServerRegistrar2
+ {
+ private readonly string _umbracoApplicationUrl;
+
+ public IEnumerable Registrations { get; private set; }
+
+ public SingleServerRegistrar()
+ {
+ _umbracoApplicationUrl = ApplicationContext.Current.UmbracoApplicationUrl;
+ Registrations = new[] { new ServerAddressImpl(_umbracoApplicationUrl) };
+ }
+
+ public ServerRole GetCurrentServerRole()
+ {
+ return ServerRole.Single;
+ }
+
+ public string GetCurrentServerUmbracoApplicationUrl()
+ {
+ return _umbracoApplicationUrl;
+ }
+
+ private class ServerAddressImpl : IServerAddress
+ {
+ public ServerAddressImpl(string serverAddress)
+ {
+ ServerAddress = serverAddress;
+ }
+
+ public string ServerAddress { get; private set; }
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 9f94796b92..6da7f4519b 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -454,6 +454,7 @@
+
@@ -1348,6 +1349,7 @@
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/packager/views/install-local.controller.js b/src/Umbraco.Web.UI.Client/src/views/packager/views/install-local.controller.js
index e5fba69a88..e34bc48ecd 100644
--- a/src/Umbraco.Web.UI.Client/src/views/packager/views/install-local.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/packager/views/install-local.controller.js
@@ -12,6 +12,7 @@
status: "",
progress:0
};
+ vm.installCompleted = false;
vm.zipFile = {
uploadStatus: "idle",
uploadProgress: 0,
@@ -137,10 +138,10 @@
localStorageService.set("packageInstallUri", "installed");
}
- //reload on next digest (after cookie)
- $timeout(function () {
- $window.location.reload(true);
- });
+ vm.installState.status = localizationService.localize("packager_installStateCompleted");
+ vm.installCompleted = true;
+
+
},
installError);
@@ -150,6 +151,13 @@
//This will return a rejection meaning that the promise change above will stop
return $q.reject();
}
+
+ vm.reloadPage = function() {
+ //reload on next digest (after cookie)
+ $timeout(function () {
+ $window.location.reload(true);
+ });
+ }
}
angular.module("umbraco").controller("Umbraco.Editors.Packages.InstallLocalController", PackagesInstallLocalController);
diff --git a/src/Umbraco.Web.UI.Client/src/views/packager/views/install-local.html b/src/Umbraco.Web.UI.Client/src/views/packager/views/install-local.html
index 499e844588..6bb7c6fb14 100644
--- a/src/Umbraco.Web.UI.Client/src/views/packager/views/install-local.html
+++ b/src/Umbraco.Web.UI.Client/src/views/packager/views/install-local.html
@@ -159,6 +159,19 @@
{{vm.installState.status}}
+
+
+
+
+
+
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/packager/views/repo.controller.js b/src/Umbraco.Web.UI.Client/src/views/packager/views/repo.controller.js
index e4afb661e3..5ae1d4bf2c 100644
--- a/src/Umbraco.Web.UI.Client/src/views/packager/views/repo.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/packager/views/repo.controller.js
@@ -30,6 +30,7 @@
vm.openLightbox = openLightbox;
vm.closeLightbox = closeLightbox;
vm.search = search;
+ vm.installCompleted = false;
var currSort = "Latest";
//used to cancel any request in progress if another one needs to take it's place
@@ -215,10 +216,8 @@
localStorageService.set("packageInstallUri", result.postInstallationPath);
}
- //reload on next digest (after cookie)
- $timeout(function() {
- window.location.reload(true);
- });
+ vm.installState.status = localizationService.localize("packager_installStateCompleted");
+ vm.installCompleted = true;
},
error);
@@ -277,6 +276,13 @@
searchDebounced();
}
+ vm.reloadPage = function () {
+ //reload on next digest (after cookie)
+ $timeout(function () {
+ window.location.reload(true);
+ });
+ }
+
init();
}
diff --git a/src/Umbraco.Web.UI.Client/src/views/packager/views/repo.html b/src/Umbraco.Web.UI.Client/src/views/packager/views/repo.html
index 3975dc96d9..e7b14182ca 100644
--- a/src/Umbraco.Web.UI.Client/src/views/packager/views/repo.html
+++ b/src/Umbraco.Web.UI.Client/src/views/packager/views/repo.html
@@ -340,6 +340,16 @@
{{vm.installState.status}}
+
+
+
+
+
diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
index 4fc01686d9..7d1ee51a4b 100644
--- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
+++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
@@ -2398,6 +2398,7 @@
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v11.0$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v12.0$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v15.0
diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml
index bdc2647563..f7ac08d837 100644
--- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml
+++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml
@@ -817,7 +817,7 @@ To manage your website, simply open the Umbraco back office and start adding con
Installing...Restarting, please wait...All done, your browser will now refresh, please wait...
-
+ Please click finish to complete installation and reload page.Paste with full formatting (Not recommended)
diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml
index 7544cacc0c..173da6cc9b 100644
--- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml
+++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml
@@ -817,6 +817,7 @@ To manage your website, simply open the Umbraco back office and start adding con
Installing...Restarting, please wait...All done, your browser will now refresh, please wait...
+ Please click finish to complete installation and reload page.Paste with full formatting (Not recommended)
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 1578ff7555..a0b112c7c7 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -2258,6 +2258,7 @@
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v11.0$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v12.0$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v15.0
diff --git a/src/umbraco.presentation.targets b/src/umbraco.presentation.targets
index c38a1da485..2a33705d6f 100644
--- a/src/umbraco.presentation.targets
+++ b/src/umbraco.presentation.targets
@@ -55,6 +55,10 @@
$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v14.0\Web\Microsoft.Web.Publishing.Tasks.dll
+
+
+ $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v15.0\Web\Microsoft.Web.Publishing.Tasks.dll
+