diff --git a/src/Umbraco.Core/ContentExtensions.cs b/src/Umbraco.Core/ContentExtensions.cs
index 4f88c2b803..910717304c 100644
--- a/src/Umbraco.Core/ContentExtensions.cs
+++ b/src/Umbraco.Core/ContentExtensions.cs
@@ -37,101 +37,6 @@ namespace Umbraco.Core
return dirty.WasPropertyDirty("Published") && entity.Published;
}
- ///
- /// Returns a list of the current contents ancestors, not including the content itself.
- ///
- /// Current content
- ///
- /// An enumerable list of objects
- public static IEnumerable Ancestors(this IContent content, IContentService contentService)
- {
- return contentService.GetAncestors(content);
- }
-
- ///
- /// Returns a list of the current contents children.
- ///
- /// Current content
- ///
- /// An enumerable list of objects
- public static IEnumerable Children(this IContent content, IContentService contentService)
- {
- return contentService.GetChildren(content.Id);
- }
-
- ///
- /// Returns a list of the current contents descendants, not including the content itself.
- ///
- /// Current content
- ///
- /// An enumerable list of objects
- public static IEnumerable Descendants(this IContent content, IContentService contentService)
- {
- return contentService.GetDescendants(content);
- }
-
- ///
- /// Returns the parent of the current content.
- ///
- /// Current content
- ///
- /// An object
- public static IContent Parent(this IContent content, IContentService contentService)
- {
- return contentService.GetById(content.ParentId);
- }
-
- #endregion
-
- #region IMedia
-
- ///
- /// Returns a list of the current medias ancestors, not including the media itself.
- ///
- /// Current media
- ///
- /// An enumerable list of objects
- public static IEnumerable Ancestors(this IMedia media, IMediaService mediaService)
- {
- return mediaService.GetAncestors(media);
- }
-
-
- ///
- /// Returns a list of the current medias children.
- ///
- /// Current media
- ///
- /// An enumerable list of objects
- public static IEnumerable Children(this IMedia media, IMediaService mediaService)
- {
- return mediaService.GetChildren(media.Id);
- }
-
-
- ///
- /// Returns a list of the current medias descendants, not including the media itself.
- ///
- /// Current media
- ///
- /// An enumerable list of objects
- public static IEnumerable Descendants(this IMedia media, IMediaService mediaService)
- {
- return mediaService.GetDescendants(media);
- }
-
-
- ///
- /// Returns the parent of the current media.
- ///
- /// Current media
- ///
- /// An object
- public static IMedia Parent(this IMedia media, IMediaService mediaService)
- {
- return mediaService.GetById(media.ParentId);
- }
-
#endregion
///
@@ -179,29 +84,7 @@ namespace Umbraco.Core
}
return false;
}
-
- ///
- /// Returns the children for the content base item
- ///
- ///
- ///
- ///
- ///
- /// This is a bit of a hack because we need to type check!
- ///
- internal static IEnumerable Children(IContentBase content, ServiceContext services)
- {
- if (content is IContent)
- {
- return services.ContentService.GetChildren(content.Id);
- }
- if (content is IMedia)
- {
- return services.MediaService.GetChildren(content.Id);
- }
- return null;
- }
-
+
///
/// Returns properties that do not belong to a group
///
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs
index f3afe99b28..b3a7c31e54 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs
@@ -99,7 +99,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
private string VariantNameSqlExpression
=> SqlContext.VisitDto((ccv, node) => ccv.Name ?? node.Text, "ccv").Sql;
- protected virtual Sql GetBaseQuery(QueryType queryType, bool current)
+ protected Sql GetBaseQuery(QueryType queryType, bool current)
{
var sql = SqlContext.Sql();
diff --git a/src/Umbraco.Core/Services/EntityXmlSerializer.cs b/src/Umbraco.Core/Services/EntityXmlSerializer.cs
index e418c8d3e6..5b64584dc6 100644
--- a/src/Umbraco.Core/Services/EntityXmlSerializer.cs
+++ b/src/Umbraco.Core/Services/EntityXmlSerializer.cs
@@ -30,7 +30,7 @@ namespace Umbraco.Core.Services
IEnumerable urlSegmentProviders,
IContent content,
bool published,
- bool withDescendants = false) // fixme take care of usage!
+ bool withDescendants = false) //fixme take care of usage! only used for the packager
{
if (contentService == null) throw new ArgumentNullException(nameof(contentService));
if (dataTypeService == null) throw new ArgumentNullException(nameof(dataTypeService));
@@ -58,9 +58,15 @@ namespace Umbraco.Core.Services
if (withDescendants)
{
- var descendants = contentService.GetDescendants(content).ToArray();
- var currentChildren = descendants.Where(x => x.ParentId == content.Id);
- SerializeDescendants(contentService, dataTypeService, userService, localizationService, urlSegmentProviders, descendants, currentChildren, xml, published);
+ const int pageSize = 500;
+ var page = 0;
+ var total = long.MaxValue;
+ while(page * pageSize < total)
+ {
+ var children = contentService.GetPagedChildren(content.Id, page++, pageSize, out total);
+ SerializeChildren(contentService, dataTypeService, userService, localizationService, urlSegmentProviders, children, xml, published);
+ }
+
}
return xml;
@@ -103,9 +109,14 @@ namespace Umbraco.Core.Services
if (withDescendants)
{
- var descendants = mediaService.GetDescendants(media).ToArray();
- var currentChildren = descendants.Where(x => x.ParentId == media.Id);
- SerializeDescendants(mediaService, dataTypeService, userService, localizationService, urlSegmentProviders, descendants, currentChildren, xml);
+ const int pageSize = 500;
+ var page = 0;
+ var total = long.MaxValue;
+ while (page * pageSize < total)
+ {
+ var children = mediaService.GetPagedChildren(media.Id, page++, pageSize, out total);
+ SerializeChildren(mediaService, dataTypeService, userService, localizationService, urlSegmentProviders, children, xml);
+ }
}
return xml;
@@ -451,7 +462,7 @@ namespace Umbraco.Core.Services
}
// exports an IContent item descendants.
- private static void SerializeDescendants(IContentService contentService, IDataTypeService dataTypeService, IUserService userService, ILocalizationService localizationService, IEnumerable urlSegmentProviders, IContent[] originalDescendants, IEnumerable children, XElement xml, bool published)
+ private static void SerializeChildren(IContentService contentService, IDataTypeService dataTypeService, IUserService userService, ILocalizationService localizationService, IEnumerable urlSegmentProviders, IEnumerable children, XElement xml, bool published)
{
foreach (var child in children)
{
@@ -459,17 +470,20 @@ namespace Umbraco.Core.Services
var childXml = Serialize(contentService, dataTypeService, userService, localizationService, urlSegmentProviders, child, published);
xml.Add(childXml);
- // capture id (out of closure) and get the grandChildren (children of the child)
- var parentId = child.Id;
- var grandChildren = originalDescendants.Where(x => x.ParentId == parentId);
-
- // recurse
- SerializeDescendants(contentService, dataTypeService, userService, localizationService, urlSegmentProviders, originalDescendants, grandChildren, childXml, published);
+ const int pageSize = 500;
+ var page = 0;
+ var total = long.MaxValue;
+ while(page * pageSize < total)
+ {
+ var grandChildren = contentService.GetPagedChildren(child.Id, page++, pageSize, out total);
+ // recurse
+ SerializeChildren(contentService, dataTypeService, userService, localizationService, urlSegmentProviders, grandChildren, childXml, published);
+ }
}
}
// exports an IMedia item descendants.
- private static void SerializeDescendants(IMediaService mediaService, IDataTypeService dataTypeService, IUserService userService, ILocalizationService localizationService, IEnumerable urlSegmentProviders, IMedia[] originalDescendants, IEnumerable children, XElement xml)
+ private static void SerializeChildren(IMediaService mediaService, IDataTypeService dataTypeService, IUserService userService, ILocalizationService localizationService, IEnumerable urlSegmentProviders, IEnumerable children, XElement xml)
{
foreach (var child in children)
{
@@ -477,12 +491,15 @@ namespace Umbraco.Core.Services
var childXml = Serialize(mediaService, dataTypeService, userService, localizationService, urlSegmentProviders, child);
xml.Add(childXml);
- // capture id (out of closure) and get the grandChildren (children of the child)
- var parentId = child.Id;
- var grandChildren = originalDescendants.Where(x => x.ParentId == parentId);
-
- // recurse
- SerializeDescendants(mediaService, dataTypeService, userService, localizationService, urlSegmentProviders, originalDescendants, grandChildren, childXml);
+ const int pageSize = 500;
+ var page = 0;
+ var total = long.MaxValue;
+ while (page * pageSize < total)
+ {
+ var grandChildren = mediaService.GetPagedChildren(child.Id, page++, pageSize, out total);
+ // recurse
+ SerializeChildren(mediaService, dataTypeService, userService, localizationService, urlSegmentProviders, grandChildren, childXml);
+ }
}
}
}
diff --git a/src/Umbraco.Core/Services/IContentService.cs b/src/Umbraco.Core/Services/IContentService.cs
index 7371686c7c..6cfc923ebe 100644
--- a/src/Umbraco.Core/Services/IContentService.cs
+++ b/src/Umbraco.Core/Services/IContentService.cs
@@ -78,26 +78,11 @@ namespace Umbraco.Core.Services
///
IEnumerable GetByIds(IEnumerable ids);
- ///
- /// Gets documents of a given document type.
- ///
- IEnumerable GetByType(int documentTypeId);
-
///
/// Gets documents at a given level.
///
IEnumerable GetByLevel(int level);
- ///
- /// Gets child documents of a given parent.
- ///
- IEnumerable GetChildren(int parentId);
-
- ///
- /// Gets child documents of a document, (partially) matching a name.
- ///
- IEnumerable GetChildren(int parentId, string name);
-
///
/// Gets the parent of a document.
///
@@ -118,16 +103,6 @@ namespace Umbraco.Core.Services
///
IEnumerable GetAncestors(IContent content);
- ///
- /// Gets descendant documents of a document.
- ///
- IEnumerable GetDescendants(int id);
-
- ///
- /// Gets descendant documents of a document.
- ///
- IEnumerable GetDescendants(IContent content);
-
///
/// Gets all versions of a document.
///
@@ -169,19 +144,8 @@ namespace Umbraco.Core.Services
///
/// Gets documents in the recycle bin.
///
- IEnumerable GetContentInRecycleBin();
-
- ///
- /// Gets child documents of a parent.
- ///
- /// The parent identifier.
- /// The page number.
- /// The page size.
- /// Total number of documents.
- /// Search text filter.
- /// Ordering infos.
- IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords,
- string filter = null, Ordering ordering = null);
+ IEnumerable GetPagedContentInRecycleBin(long pageIndex, int pageSize, out long totalRecords,
+ IQuery filter = null, Ordering ordering = null);
///
/// Gets child documents of a parent.
@@ -193,20 +157,7 @@ namespace Umbraco.Core.Services
/// Query filter.
/// Ordering infos.
IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords,
- IQuery filter, Ordering ordering = null);
-
- ///
- /// Gets descendant documents of a given parent.
- ///
- /// The parent identifier.
- /// The page number.
- /// The page size.
- /// Total number of documents.
- /// A field to order by.
- /// The ordering direction.
- /// Search text filter.
- IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords,
- string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "");
+ IQuery filter = null, Ordering ordering = null);
///
/// Gets descendant documents of a given parent.
@@ -220,7 +171,31 @@ namespace Umbraco.Core.Services
/// A flag indicating whether the ordering field is a system field.
/// Query filter.
IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords,
- string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter);
+ IQuery filter = null, Ordering ordering = null);
+
+ ///
+ /// Gets paged documents of a content content
+ ///
+ /// The page number.
+ /// The page number.
+ /// The page size.
+ /// Total number of documents.
+ /// Search text filter.
+ /// Ordering infos.
+ IEnumerable GetPagedOfType(int contentTypeId, long pageIndex, int pageSize, out long totalRecords,
+ IQuery filter, Ordering ordering = null);
+
+ ///
+ /// Gets paged documents for specified content types
+ ///
+ /// The page number.
+ /// The page number.
+ /// The page size.
+ /// Total number of documents.
+ /// Search text filter.
+ /// Ordering infos.
+ IEnumerable GetPagedOfTypes(int[] contentTypeIds, long pageIndex, int pageSize, out long totalRecords,
+ IQuery filter, Ordering ordering = null);
///
/// Counts documents of a given document type.
diff --git a/src/Umbraco.Core/Services/IMediaService.cs b/src/Umbraco.Core/Services/IMediaService.cs
index 31c2e74fd4..9cc559ccd5 100644
--- a/src/Umbraco.Core/Services/IMediaService.cs
+++ b/src/Umbraco.Core/Services/IMediaService.cs
@@ -78,27 +78,6 @@ namespace Umbraco.Core.Services
///
IMedia GetById(int id);
- ///
- /// Gets a collection of objects by Parent Id
- ///
- /// Id of the Parent to retrieve Children from
- /// An Enumerable list of objects
- IEnumerable GetChildren(int id);
-
- ///
- /// Gets a collection of objects by Parent Id
- ///
- /// Id of the Parent to retrieve Children from
- /// Page number
- /// Page size
- /// Total records query would return without paging
- /// Field to order by
- /// Direction to order by
- /// Search text filter
- /// An Enumerable list of objects
- IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords,
- string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = "");
-
///
/// Gets a collection of objects by Parent Id
///
@@ -112,37 +91,7 @@ namespace Umbraco.Core.Services
///
/// An Enumerable list of objects
IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords,
- string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter);
-
- ///
- /// Gets a collection of objects by Parent Id
- ///
- /// Id of the Parent to retrieve Children from
- /// Page number
- /// Page size
- /// Total records query would return without paging
- /// Field to order by
- /// Direction to order by
- /// Flag to indicate when ordering by system field
- /// Search text filter
- /// A list of content type Ids to filter the list by
- /// An Enumerable list of objects
- IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords,
- string orderBy, Direction orderDirection, bool orderBySystemField, string filter, int[] contentTypeFilter);
-
- ///
- /// Gets a collection of objects by Parent Id
- ///
- /// Id of the Parent to retrieve Descendants from
- /// Page number
- /// Page size
- /// Total records query would return without paging
- /// Field to order by
- /// Direction to order by
- /// Search text filter
- /// An Enumerable list of objects
- IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords,
- string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "");
+ IQuery filter = null, Ordering ordering = null);
///
/// Gets a collection of objects by Parent Id
@@ -157,21 +106,31 @@ namespace Umbraco.Core.Services
///
/// An Enumerable list of objects
IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords,
- string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter);
+ IQuery filter = null, Ordering ordering = null);
///
- /// Gets descendants of a object by its Id
+ /// Gets paged documents of a content content
///
- /// Id of the Parent to retrieve descendants from
- /// An Enumerable flat list of objects
- IEnumerable GetDescendants(int id);
+ /// The page number.
+ /// The page number.
+ /// The page size.
+ /// Total number of documents.
+ /// Search text filter.
+ /// Ordering infos.
+ IEnumerable GetPagedOfType(int contentTypeId, long pageIndex, int pageSize, out long totalRecords,
+ IQuery filter = null, Ordering ordering = null);
///
- /// Gets a collection of objects by the Id of the
+ /// Gets paged documents for specified content types
///
- /// Id of the
- /// An Enumerable list of objects
- IEnumerable GetMediaOfMediaType(int id);
+ /// The page number.
+ /// The page number.
+ /// The page size.
+ /// Total number of documents.
+ /// Search text filter.
+ /// Ordering infos.
+ IEnumerable GetPagedOfTypes(int[] contentTypeIds, long pageIndex, int pageSize, out long totalRecords,
+ IQuery filter = null, Ordering ordering = null);
///
/// Gets a collection of objects, which reside at the first level / root
@@ -183,7 +142,8 @@ namespace Umbraco.Core.Services
/// Gets a collection of an objects, which resides in the Recycle Bin
///
/// An Enumerable list of objects
- IEnumerable GetMediaInRecycleBin();
+ IEnumerable GetPagedMediaInRecycleBin(long pageIndex, int pageSize, out long totalRecords,
+ IQuery filter = null, Ordering ordering = null);
///
/// Moves an object to a new location
@@ -321,13 +281,6 @@ namespace Umbraco.Core.Services
/// An Enumerable list of objects
IEnumerable GetAncestors(IMedia media);
- ///
- /// Gets descendants of a object by its Id
- ///
- /// The Parent object to retrieve descendants from
- /// An Enumerable flat list of objects
- IEnumerable GetDescendants(IMedia media);
-
///
/// Gets the parent of the current media as an item.
///
diff --git a/src/Umbraco.Core/Services/Implement/ContentService.cs b/src/Umbraco.Core/Services/Implement/ContentService.cs
index 9bb8e6720e..386c76db88 100644
--- a/src/Umbraco.Core/Services/Implement/ContentService.cs
+++ b/src/Umbraco.Core/Services/Implement/ContentService.cs
@@ -405,28 +405,40 @@ namespace Umbraco.Core.Services.Implement
}
}
- ///
- /// Gets a collection of objects by the Id of the
- ///
- /// Id of the
- /// An Enumerable list of objects
- public IEnumerable GetByType(int id)
+ ///
+ public IEnumerable GetPagedOfType(int contentTypeId, long pageIndex, int pageSize, out long totalRecords
+ , IQuery filter = null, Ordering ordering = null)
{
+ if(pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex));
+ if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize));
+
+ if (ordering == null)
+ ordering = Ordering.By("sortOrder");
+
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
scope.ReadLock(Constants.Locks.ContentTree);
- var query = Query().Where(x => x.ContentTypeId == id);
- return _documentRepository.Get(query);
+ return _documentRepository.GetPage(
+ Query().Where(x => x.ContentTypeId == contentTypeId),
+ pageIndex, pageSize, out totalRecords, filter, ordering);
}
}
- internal IEnumerable GetPublishedContentOfContentType(int id)
+ ///
+ public IEnumerable GetPagedOfTypes(int[] contentTypeIds, long pageIndex, int pageSize, out long totalRecords, IQuery filter, Ordering ordering = null)
{
+ if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex));
+ if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize));
+
+ if (ordering == null)
+ ordering = Ordering.By("sortOrder");
+
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
scope.ReadLock(Constants.Locks.ContentTree);
- var query = Query().Where(x => x.ContentTypeId == id);
- return _documentRepository.Get(query);
+ return _documentRepository.GetPage(
+ Query().Where(x => contentTypeIds.Contains(x.ContentTypeId)),
+ pageIndex, pageSize, out totalRecords, filter, ordering);
}
}
@@ -536,21 +548,6 @@ namespace Umbraco.Core.Services.Implement
}
}
- ///
- /// Gets a collection of objects by Parent Id
- ///
- /// Id of the Parent to retrieve Children from
- /// An Enumerable list of objects
- public IEnumerable GetChildren(int id)
- {
- using (var scope = ScopeProvider.CreateScope(autoComplete: true))
- {
- scope.ReadLock(Constants.Locks.ContentTree);
- var query = Query().Where(x => x.ParentId == id);
- return _documentRepository.Get(query).OrderBy(x => x.SortOrder);
- }
- }
-
///
/// Gets a collection of published objects by Parent Id
///
@@ -568,18 +565,7 @@ namespace Umbraco.Core.Services.Implement
///
public IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren,
- string filter = null, Ordering ordering = null)
- {
- var filterQuery = filter.IsNullOrWhiteSpace()
- ? null
- : Query().Where(x => x.Name.Contains(filter));
-
- return GetPagedChildren(id, pageIndex, pageSize, out totalChildren, filterQuery, ordering);
- }
-
- ///
- public IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren,
- IQuery filter, Ordering ordering = null)
+ IQuery filter = null, Ordering ordering = null)
{
if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex));
if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize));
@@ -597,27 +583,16 @@ namespace Umbraco.Core.Services.Implement
}
///
- public IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "")
+ public IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren,
+ IQuery filter = null, Ordering ordering = null)
{
- var filterQuery = filter.IsNullOrWhiteSpace()
- ? null
- : Query().Where(x => x.Name.Contains(filter));
-
- return GetPagedDescendants(id, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, true, filterQuery);
- }
-
- ///
- public IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter)
- {
- if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex));
- if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize));
+ if (ordering == null)
+ ordering = Ordering.By("Path");
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
scope.ReadLock(Constants.Locks.ContentTree);
- var query = Query();
-
//if the id is System Root, then just get all
if (id != Constants.System.Root)
{
@@ -627,65 +602,24 @@ namespace Umbraco.Core.Services.Implement
totalChildren = 0;
return Enumerable.Empty();
}
- query.Where(x => x.Path.SqlStartsWith($"{contentPath[0].Path},", TextColumnType.NVarchar));
+ return GetPagedDescendantsLocked(contentPath[0].Path, pageIndex, pageSize, out totalChildren, filter, ordering);
}
-
- return _documentRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filter, Ordering.By(orderBy, orderDirection, isCustomField: !orderBySystemField));
+ return GetPagedDescendantsLocked(null, pageIndex, pageSize, out totalChildren, filter, ordering);
}
}
- ///
- /// Gets a collection of objects by its name or partial name
- ///
- /// Id of the Parent to retrieve Children from
- /// Full or partial name of the children
- /// An Enumerable list of objects
- public IEnumerable GetChildren(int parentId, string name)
+ private IEnumerable GetPagedDescendantsLocked(string contentPath, long pageIndex, int pageSize, out long totalChildren,
+ IQuery filter, Ordering ordering)
{
- using (var scope = ScopeProvider.CreateScope(autoComplete: true))
- {
- scope.ReadLock(Constants.Locks.ContentTree);
- var query = Query().Where(x => x.ParentId == parentId && x.Name.Contains(name));
- return _documentRepository.Get(query);
- }
- }
+ if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex));
+ if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize));
+ if (ordering == null) throw new ArgumentNullException(nameof(ordering));
- ///
- /// Gets a collection of objects by Parent Id
- ///
- /// Id of the Parent to retrieve Descendants from
- /// An Enumerable list of objects
- public IEnumerable GetDescendants(int id)
- {
- using (var scope = ScopeProvider.CreateScope(autoComplete: true))
- {
- scope.ReadLock(Constants.Locks.ContentTree);
- var content = GetById(id);
- if (content == null)
- {
- scope.Complete(); // else causes rollback
- return Enumerable.Empty();
- }
- var pathMatch = content.Path + ",";
- var query = Query().Where(x => x.Id != content.Id && x.Path.StartsWith(pathMatch));
- return _documentRepository.Get(query);
- }
- }
+ var query = Query();
+ if (!contentPath.IsNullOrWhiteSpace())
+ query.Where(x => x.Path.SqlStartsWith($"{contentPath},", TextColumnType.NVarchar));
- ///
- /// Gets a collection of objects by Parent Id
- ///
- /// item to retrieve Descendants from
- /// An Enumerable list of objects
- public IEnumerable GetDescendants(IContent content)
- {
- using (var scope = ScopeProvider.CreateScope(autoComplete: true))
- {
- scope.ReadLock(Constants.Locks.ContentTree);
- var pathMatch = content.Path + ",";
- var query = Query().Where(x => x.Id != content.Id && x.Path.StartsWith(pathMatch));
- return _documentRepository.Get(query);
- }
+ return _documentRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filter, ordering);
}
///
@@ -772,13 +706,17 @@ namespace Umbraco.Core.Services.Implement
/// Gets a collection of an objects, which resides in the Recycle Bin
///
/// An Enumerable list of objects
- public IEnumerable GetContentInRecycleBin()
+ public IEnumerable GetPagedContentInRecycleBin(long pageIndex, int pageSize, out long totalRecords,
+ IQuery filter = null, Ordering ordering = null)
{
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
+ if (ordering == null)
+ ordering = Ordering.By("Path");
+
scope.ReadLock(Constants.Locks.ContentTree);
var query = Query().Where(x => x.Path.StartsWith(Constants.System.RecycleBinContentPathPrefix));
- return _documentRepository.Get(query);
+ return _documentRepository.GetPage(query, pageIndex, pageSize, out totalRecords, filter, ordering);
}
}
@@ -871,7 +809,7 @@ namespace Umbraco.Core.Services.Implement
var langs = string.Join(", ", _languageRepository.GetMany()
.Where(x => culturesChanging.InvariantContains(x.IsoCode))
.Select(x => x.CultureName));
- Audit(AuditType.SaveVariant, userId, content.Id, $"Saved languagues: {langs}", langs);
+ Audit(AuditType.SaveVariant, userId, content.Id, $"Saved languages: {langs}", langs);
}
else
Audit(AuditType.Save, userId, content.Id);
@@ -1355,27 +1293,35 @@ namespace Umbraco.Core.Services.Implement
// if one fails, abort its branch
var exclude = new HashSet();
- //fixme: should be paged to not overwhelm the database (timeouts)
- foreach (var d in GetDescendants(document))
+ const int pageSize = 500;
+ var page = 0;
+ var total = long.MaxValue;
+ while (page * pageSize < total)
{
- // if parent is excluded, exclude document and ignore
- // if not forcing, and not publishing, exclude document and ignore
- if (exclude.Contains(d.ParentId) || !force && !d.Published)
+ var descendants = GetPagedDescendants(document.Id, page++, pageSize, out total);
+
+ foreach (var d in descendants)
{
+ // if parent is excluded, exclude document and ignore
+ // if not forcing, and not publishing, exclude document and ignore
+ if (exclude.Contains(d.ParentId) || !force && !d.Published)
+ {
+ exclude.Add(d.Id);
+ continue;
+ }
+
+ // no need to check path here,
+ // 1. because we know the parent is path-published (we just published it)
+ // 2. because it would not work as nothing's been written out to the db until the uow completes
+ result = SaveAndPublishBranchOne(scope, d, editing, publishCultures, false, publishedDocuments, evtMsgs, userId);
+ results.Add(result);
+ if (result.Success) continue;
+
+ // abort branch
exclude.Add(d.Id);
- continue;
}
-
- // no need to check path here,
- // 1. because we know the parent is path-published (we just published it)
- // 2. because it would not work as nothing's been written out to the db until the uow completes
- result = SaveAndPublishBranchOne(scope, d, editing, publishCultures, false, publishedDocuments, evtMsgs, userId);
- results.Add(result);
- if (result.Success) continue;
-
- // abort branch
- exclude.Add(d.Id);
}
+
scope.Events.Dispatch(TreeChanged, this, new TreeChange(document, TreeChangeTypes.RefreshBranch).ToEventArgs());
scope.Events.Dispatch(Published, this, new PublishEventArgs(publishedDocuments, false, false), "Published");
@@ -1458,25 +1404,8 @@ namespace Umbraco.Core.Services.Implement
private void DeleteLocked(IScope scope, IContent content)
{
- // then recursively delete descendants, bottom-up
- // just repository.Delete + an event
- var stack = new Stack();
- stack.Push(content);
- var level = 1;
- while (stack.Count > 0)
+ void DoDelete(IContent c)
{
- var c = stack.Peek();
- IContent[] cc;
- if (c.Level == level)
- while ((cc = c.Children(this).ToArray()).Length > 0)
- {
- foreach (var ci in cc)
- stack.Push(ci);
- c = cc[cc.Length - 1];
- }
- c = stack.Pop();
- level = c.Level;
-
_documentRepository.Delete(c);
var args = new DeleteEventArgs(c, false); // raise event & get flagged files
scope.Events.Dispatch(Deleted, this, args, nameof(Deleted));
@@ -1485,6 +1414,18 @@ namespace Umbraco.Core.Services.Implement
_mediaFileSystem.DeleteFiles(args.MediaFilesToDelete, // remove flagged files
(file, e) => Logger.Error(e, "An error occurred while deleting file attached to nodes: {File}", file));
}
+
+ const int pageSize = 500;
+ var page = 0;
+ var total = long.MaxValue;
+ while (page * pageSize < total)
+ {
+ //get descendants - ordered from deepest to shallowest
+ var descendants = GetPagedDescendants(content.Id, page, pageSize, out total, ordering: Ordering.By("Path", Direction.Descending));
+ foreach (var c in descendants)
+ DoDelete(c);
+ }
+ DoDelete(content);
}
//TODO:
@@ -1694,8 +1635,8 @@ namespace Umbraco.Core.Services.Implement
moves.Add(Tuple.Create(content, content.Path)); // capture original path
- // get before moving, in case uow is immediate
- var descendants = GetDescendants(content);
+ //need to store the original path to lookup descendants based on it below
+ var originalPath = content.Path;
// these will be updated by the repo because we changed parentId
//content.Path = (parent == null ? "-1" : parent.Path) + "," + content.Id;
@@ -1708,22 +1649,28 @@ namespace Umbraco.Core.Services.Implement
//paths[content.Id] = content.Path;
paths[content.Id] = (parent == null ? (parentId == Constants.System.RecycleBinContent ? "-1,-20" : "-1") : parent.Path) + "," + content.Id;
- foreach (var descendant in descendants)
+ const int pageSize = 500;
+ var page = 0;
+ var total = long.MaxValue;
+ while(page * pageSize < total)
{
- moves.Add(Tuple.Create(descendant, descendant.Path)); // capture original path
+ var descendants = GetPagedDescendantsLocked(originalPath, page++, pageSize, out total, null, Ordering.By("Path", Direction.Ascending));
+ foreach (var descendant in descendants)
+ {
+ moves.Add(Tuple.Create(descendant, descendant.Path)); // capture original path
- // update path and level since we do not update parentId
- if (paths.ContainsKey(descendant.ParentId) == false)
- Console.WriteLine("oops on " + descendant.ParentId + " for " + content.Path + " " + parent?.Path);
- descendant.Path = paths[descendant.Id] = paths[descendant.ParentId] + "," + descendant.Id;
- Console.WriteLine("path " + descendant.Id + " = " + paths[descendant.Id]);
- descendant.Level += levelDelta;
- PerformMoveContentLocked(descendant, userId, trash);
+ // update path and level since we do not update parentId
+ descendant.Path = paths[descendant.Id] = paths[descendant.ParentId] + "," + descendant.Id;
+ descendant.Level += levelDelta;
+ PerformMoveContentLocked(descendant, userId, trash);
+ }
}
+
}
private void PerformMoveContentLocked(IContent content, int userId, bool? trash)
{
+ //fixme no casting
if (trash.HasValue) ((ContentBase) content).Trashed = trash.Value;
content.WriterId = userId;
_documentRepository.Save(content);
@@ -1852,29 +1799,36 @@ namespace Umbraco.Core.Services.Implement
if (recursive) // process descendants
{
- foreach (var descendant in GetDescendants(content))
+ const int pageSize = 500;
+ var page = 0;
+ var total = long.MaxValue;
+ while(page * pageSize < total)
{
- // if parent has not been copied, skip, else gets its copy id
- if (idmap.TryGetValue(descendant.ParentId, out parentId) == false) continue;
+ var descendants = GetPagedDescendants(content.Id, page++, pageSize, out total);
+ foreach (var descendant in descendants)
+ {
+ // if parent has not been copied, skip, else gets its copy id
+ if (idmap.TryGetValue(descendant.ParentId, out parentId) == false) continue;
- var descendantCopy = descendant.DeepCloneWithResetIdentities();
- descendantCopy.ParentId = parentId;
+ var descendantCopy = descendant.DeepCloneWithResetIdentities();
+ descendantCopy.ParentId = parentId;
- if (scope.Events.DispatchCancelable(Copying, this, new CopyEventArgs(descendant, descendantCopy, parentId)))
- continue;
+ if (scope.Events.DispatchCancelable(Copying, this, new CopyEventArgs(descendant, descendantCopy, parentId)))
+ continue;
- // a copy is not published (but not really unpublishing either)
- // update the create author and last edit author
- if (descendantCopy.Published)
- ((Content) descendantCopy).Published = false;
- descendantCopy.CreatorId = userId;
- descendantCopy.WriterId = userId;
+ // a copy is not published (but not really unpublishing either)
+ // update the create author and last edit author
+ if (descendantCopy.Published)
+ ((Content)descendantCopy).Published = false;
+ descendantCopy.CreatorId = userId;
+ descendantCopy.WriterId = userId;
- // save and flush (see above)
- _documentRepository.Save(descendantCopy);
+ // save and flush (see above)
+ _documentRepository.Save(descendantCopy);
- copies.Add(Tuple.Create(descendant, descendantCopy));
- idmap[descendant.Id] = descendantCopy.Id;
+ copies.Add(Tuple.Create(descendant, descendantCopy));
+ idmap[descendant.Id] = descendantCopy.Id;
+ }
}
}
diff --git a/src/Umbraco.Core/Services/Implement/MediaService.cs b/src/Umbraco.Core/Services/Implement/MediaService.cs
index da04f41e18..5f35e35acf 100644
--- a/src/Umbraco.Core/Services/Implement/MediaService.cs
+++ b/src/Umbraco.Core/Services/Implement/MediaService.cs
@@ -364,18 +364,39 @@ namespace Umbraco.Core.Services.Implement
}
}
- ///
- /// Gets a collection of objects by the Id of the
- ///
- /// Id of the
- /// An Enumerable list of objects
- public IEnumerable GetMediaOfMediaType(int id)
+ ///
+ public IEnumerable GetPagedOfType(int contentTypeId, long pageIndex, int pageSize, out long totalRecords, IQuery filter = null, Ordering ordering = null)
{
+ if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex));
+ if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize));
+
+ if (ordering == null)
+ ordering = Ordering.By("sortOrder");
+
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
- scope.ReadLock(Constants.Locks.MediaTree);
- var query = Query().Where(x => x.ContentTypeId == id);
- return _mediaRepository.Get(query);
+ scope.ReadLock(Constants.Locks.ContentTree);
+ return _mediaRepository.GetPage(
+ Query().Where(x => x.ContentTypeId == contentTypeId),
+ pageIndex, pageSize, out totalRecords, filter, ordering);
+ }
+ }
+
+ ///
+ public IEnumerable GetPagedOfTypes(int[] contentTypeIds, long pageIndex, int pageSize, out long totalRecords, IQuery filter = null, Ordering ordering = null)
+ {
+ if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex));
+ if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize));
+
+ if (ordering == null)
+ ordering = Ordering.By("sortOrder");
+
+ using (var scope = ScopeProvider.CreateScope(autoComplete: true))
+ {
+ scope.ReadLock(Constants.Locks.ContentTree);
+ return _mediaRepository.GetPage(
+ Query().Where(x => contentTypeIds.Contains(x.ContentTypeId)),
+ pageIndex, pageSize, out totalRecords, filter, ordering);
}
}
@@ -460,149 +481,36 @@ namespace Umbraco.Core.Services.Implement
}
}
- ///
- /// Gets a collection of objects by Parent Id
- ///
- /// Id of the Parent to retrieve Children from
- /// An Enumerable list of objects
- public IEnumerable GetChildren(int id)
- {
- using (var scope = ScopeProvider.CreateScope(autoComplete: true))
- {
- scope.ReadLock(Constants.Locks.MediaTree);
- var query = Query().Where(x => x.ParentId == id);
- return _mediaRepository.Get(query).OrderBy(x => x.SortOrder);
- }
- }
-
- ///
- /// Gets a collection of objects by Parent Id
- ///
- /// Id of the Parent to retrieve Children from
- /// Page index (zero based)
- /// Page size
- /// Total records query would return without paging
- /// Field to order by
- /// Direction to order by
- /// Search text filter
- /// An Enumerable list of objects
- public IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy, Direction orderDirection, string filter = "")
- {
- var filterQuery = filter.IsNullOrWhiteSpace()
- ? null
- : Query().Where(x => x.Name.Contains(filter));
-
- return GetPagedChildren(id, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, true, filterQuery);
- }
-
- ///
- /// Gets a collection of objects by Parent Id
- ///
- /// Id of the Parent to retrieve Children from
- /// Page index (zero based)
- /// Page size
- /// Total records query would return without paging
- /// Field to order by
- /// Direction to order by
- /// Flag to indicate when ordering by system field
- ///
- /// An Enumerable list of objects
- public IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter)
+ ///
+ public IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren,
+ IQuery filter = null, Ordering ordering = null)
{
if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex));
if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize));
+ if (ordering == null)
+ ordering = Ordering.By("sortOrder");
+
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
scope.ReadLock(Constants.Locks.MediaTree);
var query = Query().Where(x => x.ParentId == id);
- return _mediaRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filter, Ordering.By(orderBy, orderDirection, isCustomField: !orderBySystemField));
+ return _mediaRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filter, ordering);
}
}
- ///
- /// Gets a collection of objects by Parent Id
- ///
- /// Id of the Parent to retrieve Children from
- /// Page number
- /// Page size
- /// Total records query would return without paging
- /// Field to order by
- /// Direction to order by
- /// Flag to indicate when ordering by system field
- /// Search text filter
- /// A list of content type Ids to filter the list by
- /// An Enumerable list of objects
- public IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy, Direction orderDirection, bool orderBySystemField, string filter, int[] contentTypeFilter)
+ ///
+ public IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren,
+ IQuery filter = null, Ordering ordering = null)
{
- if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex));
- if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize));
+ if (ordering == null)
+ ordering = Ordering.By("Path");
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
scope.ReadLock(Constants.Locks.MediaTree);
- var query = Query();
- // always check for a parent - else it will also get decendants (and then you should use the GetPagedDescendants method)
-
- query.Where(x => x.ParentId == id);
-
- if (contentTypeFilter != null && contentTypeFilter.Length > 0)
- {
- query.Where(x => contentTypeFilter.Contains(x.ContentTypeId));
- }
-
- var filterQuery = filter.IsNullOrWhiteSpace()
- ? null
- : Query().Where(x => x.Name.Contains(filter));
- return _mediaRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filterQuery, Ordering.By(orderBy, orderDirection, isCustomField: !orderBySystemField));
- }
- }
-
- ///
- /// Gets a collection of objects by Parent Id
- ///
- /// Id of the Parent to retrieve Descendants from
- /// Page number
- /// Page size
- /// Total records query would return without paging
- /// Field to order by
- /// Direction to order by
- /// Search text filter
- /// An Enumerable list of objects
- public IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "")
- {
- var filterQuery = filter.IsNullOrWhiteSpace()
- ? null
- : Query().Where(x => x.Name.Contains(filter));
-
- return GetPagedDescendants(id, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, true, filterQuery);
- }
-
- ///
- /// Gets a collection of objects by Parent Id
- ///
- /// Id of the Parent to retrieve Descendants from
- /// Page number
- /// Page size
- /// Total records query would return without paging
- /// Field to order by
- /// Direction to order by
- /// Flag to indicate when ordering by system field
- ///
- /// An Enumerable list of objects
- public IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter)
- {
- if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex));
- if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize));
-
- using (var scope = ScopeProvider.CreateScope(autoComplete: true))
- {
- scope.ReadLock(Constants.Locks.MediaTree);
-
- var query = Query();
-
//if the id is System Root, then just get all
if (id != Constants.System.Root)
{
@@ -612,47 +520,24 @@ namespace Umbraco.Core.Services.Implement
totalChildren = 0;
return Enumerable.Empty();
}
- query.Where(x => x.Path.SqlStartsWith(mediaPath[0].Path + ",", TextColumnType.NVarchar));
+ return GetPagedDescendantsLocked(mediaPath[0].Path, pageIndex, pageSize, out totalChildren, filter, ordering);
}
-
- return _mediaRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filter, Ordering.By(orderBy, orderDirection, isCustomField: !orderBySystemField));
+ return GetPagedDescendantsLocked(null, pageIndex, pageSize, out totalChildren, filter, ordering);
}
}
- ///
- /// Gets descendants of a object by its Id
- ///
- /// Id of the Parent to retrieve descendants from
- /// An Enumerable flat list of objects
- public IEnumerable GetDescendants(int id)
+ private IEnumerable GetPagedDescendantsLocked(string mediaPath, long pageIndex, int pageSize, out long totalChildren,
+ IQuery filter, Ordering ordering)
{
- using (var scope = ScopeProvider.CreateScope(autoComplete: true))
- {
- scope.ReadLock(Constants.Locks.MediaTree);
- var media = GetById(id);
- if (media == null)
- return Enumerable.Empty();
+ if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex));
+ if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize));
+ if (ordering == null) throw new ArgumentNullException(nameof(ordering));
- var pathMatch = media.Path + ",";
- var query = Query().Where(x => x.Id != media.Id && x.Path.StartsWith(pathMatch));
- return _mediaRepository.Get(query);
- }
- }
+ var query = Query();
+ if (!mediaPath.IsNullOrWhiteSpace())
+ query.Where(x => x.Path.SqlStartsWith(mediaPath + ",", TextColumnType.NVarchar));
- ///
- /// Gets descendants of a object by its Id
- ///
- /// The Parent object to retrieve descendants from
- /// An Enumerable flat list of objects
- public IEnumerable GetDescendants(IMedia media)
- {
- using (var scope = ScopeProvider.CreateScope(autoComplete: true))
- {
- scope.ReadLock(Constants.Locks.MediaTree);
- var pathMatch = media.Path + ",";
- var query = Query().Where(x => x.Id != media.Id && x.Path.StartsWith(pathMatch));
- return _mediaRepository.Get(query);
- }
+ return _mediaRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filter, ordering);
}
///
@@ -694,17 +579,18 @@ namespace Umbraco.Core.Services.Implement
}
}
- ///
- /// Gets a collection of an objects, which resides in the Recycle Bin
- ///
- /// An Enumerable list of objects
- public IEnumerable GetMediaInRecycleBin()
+ ///
+ public IEnumerable GetPagedMediaInRecycleBin(long pageIndex, int pageSize, out long totalRecords,
+ IQuery filter = null, Ordering ordering = null)
{
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
+ if (ordering == null)
+ ordering = Ordering.By("Path");
+
scope.ReadLock(Constants.Locks.MediaTree);
var query = Query().Where(x => x.Path.StartsWith(Constants.System.RecycleBinMediaPathPrefix));
- return _mediaRepository.Get(query);
+ return _mediaRepository.GetPage(query, pageIndex, pageSize, out totalRecords, filter, ordering);
}
}
@@ -865,25 +751,8 @@ namespace Umbraco.Core.Services.Implement
private void DeleteLocked(IScope scope, IMedia media)
{
- // then recursively delete descendants, bottom-up
- // just repository.Delete + an event
- var stack = new Stack();
- stack.Push(media);
- var level = 1;
- while (stack.Count > 0)
+ void DoDelete(IMedia c)
{
- var c = stack.Peek();
- IMedia[] cc;
- if (c.Level == level)
- while ((cc = c.Children(this).ToArray()).Length > 0)
- {
- foreach (var ci in cc)
- stack.Push(ci);
- c = cc[cc.Length - 1];
- }
- c = stack.Pop();
- level = c.Level;
-
_mediaRepository.Delete(c);
var args = new DeleteEventArgs(c, false); // raise event & get flagged files
scope.Events.Dispatch(Deleted, this, args);
@@ -891,6 +760,18 @@ namespace Umbraco.Core.Services.Implement
_mediaFileSystem.DeleteFiles(args.MediaFilesToDelete, // remove flagged files
(file, e) => Logger.Error(e, "An error occurred while deleting file attached to nodes: {File}", file));
}
+
+ const int pageSize = 500;
+ var page = 0;
+ var total = long.MaxValue;
+ while(page * pageSize < total)
+ {
+ //get descendants - ordered from deepest to shallowest
+ var descendants = GetPagedDescendants(media.Id, page, pageSize, out total, ordering: Ordering.By("Path", Direction.Descending));
+ foreach (var c in descendants)
+ DoDelete(c);
+ }
+ DoDelete(media);
}
//TODO:
@@ -1100,8 +981,8 @@ namespace Umbraco.Core.Services.Implement
moves.Add(Tuple.Create(media, media.Path)); // capture original path
- // get before moving, in case uow is immediate
- var descendants = GetDescendants(media);
+ //need to store the original path to lookup descendants based on it below
+ var originalPath = media.Path;
// these will be updated by the repo because we changed parentId
//media.Path = (parent == null ? "-1" : parent.Path) + "," + media.Id;
@@ -1114,14 +995,21 @@ namespace Umbraco.Core.Services.Implement
//paths[media.Id] = media.Path;
paths[media.Id] = (parent == null ? (parentId == Constants.System.RecycleBinMedia ? "-1,-21" : "-1") : parent.Path) + "," + media.Id;
- foreach (var descendant in descendants)
+ const int pageSize = 500;
+ var page = 0;
+ var total = long.MaxValue;
+ while (page * pageSize < total)
{
- moves.Add(Tuple.Create(descendant, descendant.Path)); // capture original path
+ var descendants = GetPagedDescendantsLocked(originalPath, page++, pageSize, out total, null, Ordering.By("Path", Direction.Ascending));
+ foreach (var descendant in descendants)
+ {
+ moves.Add(Tuple.Create(descendant, descendant.Path)); // capture original path
- // update path and level since we do not update parentId
- descendant.Path = paths[descendant.Id] = paths[descendant.ParentId] + "," + descendant.Id;
- descendant.Level += levelDelta;
- PerformMoveMediaLocked(descendant, userId, trash);
+ // update path and level since we do not update parentId
+ descendant.Path = paths[descendant.Id] = paths[descendant.ParentId] + "," + descendant.Id;
+ descendant.Level += levelDelta;
+ PerformMoveMediaLocked(descendant, userId, trash);
+ }
}
}
diff --git a/src/Umbraco.Core/Services/Implement/MemberService.cs b/src/Umbraco.Core/Services/Implement/MemberService.cs
index 3fd714f974..5a644cfec1 100644
--- a/src/Umbraco.Core/Services/Implement/MemberService.cs
+++ b/src/Umbraco.Core/Services/Implement/MemberService.cs
@@ -393,12 +393,14 @@ namespace Umbraco.Core.Services.Implement
// fixme get rid of string filter?
- public IEnumerable GetAll(long pageIndex, int pageSize, out long totalRecords, string orderBy, Direction orderDirection, string memberTypeAlias = null, string filter = "")
+ public IEnumerable GetAll(long pageIndex, int pageSize, out long totalRecords,
+ string orderBy, Direction orderDirection, string memberTypeAlias = null, string filter = "")
{
return GetAll(pageIndex, pageSize, out totalRecords, orderBy, orderDirection, true, memberTypeAlias, filter);
}
- public IEnumerable GetAll(long pageIndex, int pageSize, out long totalRecords, string orderBy, Direction orderDirection, bool orderBySystemField, string memberTypeAlias, string filter)
+ public IEnumerable GetAll(long pageIndex, int pageSize, out long totalRecords,
+ string orderBy, Direction orderDirection, bool orderBySystemField, string memberTypeAlias, string filter)
{
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
diff --git a/src/Umbraco.Examine/UmbracoContentIndexer.cs b/src/Umbraco.Examine/UmbracoContentIndexer.cs
index 94982c8591..fab9f226a4 100644
--- a/src/Umbraco.Examine/UmbracoContentIndexer.cs
+++ b/src/Umbraco.Examine/UmbracoContentIndexer.cs
@@ -258,7 +258,8 @@ namespace Umbraco.Examine
else
{
//add the published filter
- descendants = ContentService.GetPagedDescendants(contentParentId, pageIndex, pageSize, out total, "Path", Direction.Ascending, true, _publishedQuery);
+ descendants = ContentService.GetPagedDescendants(contentParentId, pageIndex, pageSize, out total,
+ _publishedQuery, Ordering.By("Path", Direction.Ascending));
}
//if specific types are declared we need to post filter them
diff --git a/src/Umbraco.Examine/UmbracoExamineIndexer.cs b/src/Umbraco.Examine/UmbracoExamineIndexer.cs
index 64fd7b5c71..a4c1fb4336 100644
--- a/src/Umbraco.Examine/UmbracoExamineIndexer.cs
+++ b/src/Umbraco.Examine/UmbracoExamineIndexer.cs
@@ -418,7 +418,7 @@ namespace Umbraco.Examine
//icon
if (e.IndexItem.ValueSet.Values.TryGetValue("icon", out var icon) && e.IndexItem.ValueSet.Values.ContainsKey(IconFieldName) == false)
{
- e.IndexItem.ValueSet.Values[IconFieldName] = new List
[TestFixture]
- [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true, WithApplication = true)]
+ [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest,
+ PublishedRepositoryEvents = true,
+ WithApplication = true,
+ Logger = UmbracoTestOptions.Logger.Console)]
public class ContentServiceTests : TestWithSomeContentBase
{
//TODO Add test to verify there is only ONE newest document/content in {Constants.DatabaseSchema.Tables.Document} table after updating.
@@ -1038,37 +1041,6 @@ namespace Umbraco.Tests.Services
Assert.That(contents.Count(), Is.GreaterThanOrEqualTo(2));
}
- [Test]
- public void Can_Get_Children_Of_Content_Id()
- {
- // Arrange
- var contentService = ServiceContext.ContentService;
-
- // Act
- var contents = contentService.GetChildren(NodeDto.NodeIdSeed + 2).ToList();
-
- // Assert
- Assert.That(contents, Is.Not.Null);
- Assert.That(contents.Any(), Is.True);
- Assert.That(contents.Count(), Is.GreaterThanOrEqualTo(2));
- }
-
- [Test]
- public void Can_Get_Descendents_Of_Content()
- {
- // Arrange
- var contentService = ServiceContext.ContentService;
- var hierarchy = CreateContentHierarchy();
- contentService.Save(hierarchy, 0);
-
- // Act
- var contents = contentService.GetDescendants(NodeDto.NodeIdSeed + 2).ToList();
-
- // Assert
- Assert.That(contents, Is.Not.Null);
- Assert.That(contents.Any(), Is.True);
- Assert.That(contents.Count(), Is.EqualTo(52));
- }
[Test]
public void Can_Get_All_Versions_Of_Content()
@@ -1200,7 +1172,7 @@ namespace Umbraco.Tests.Services
var contentService = ServiceContext.ContentService;
// Act
- var contents = contentService.GetContentInRecycleBin().ToList();
+ var contents = contentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList();
// Assert
Assert.That(contents, Is.Not.Null);
@@ -1240,7 +1212,7 @@ namespace Umbraco.Tests.Services
{
// Arrange
- var langUk = new Language("en-UK") { IsDefault = true };
+ var langUk = new Language("en-GB") { IsDefault = true };
var langFr = new Language("fr-FR");
ServiceContext.LocalizationService.Save(langFr);
@@ -1476,8 +1448,16 @@ namespace Umbraco.Tests.Services
var parent = contentService.GetById(parentId);
Console.WriteLine(" " + parent.Id);
- foreach (var x in contentService.GetDescendants(parent))
- Console.WriteLine(" ".Substring(0, x.Level) + x.Id);
+ const int pageSize = 500;
+ var page = 0;
+ var total = long.MaxValue;
+ while(page * pageSize < total)
+ {
+ var descendants = contentService.GetPagedDescendants(parent.Id, page++, pageSize, out total);
+ foreach (var x in descendants)
+ Console.WriteLine(" ".Substring(0, x.Level) + x.Id);
+ }
+
Console.WriteLine();
// publish parent & its branch
@@ -1492,7 +1472,7 @@ namespace Umbraco.Tests.Services
Assert.IsTrue(parentPublished.All(x => x.Success));
Assert.IsTrue(parent.Published);
- var children = contentService.GetChildren(parentId);
+ var children = contentService.GetPagedChildren(parentId, 0, 500, out var totalChildren); //we only want the first so page size, etc.. is abitrary
// children are published including ... that was released 5 mins ago
Assert.IsTrue(children.First(x => x.Id == NodeDto.NodeIdSeed + 4).Published);
@@ -1738,7 +1718,7 @@ namespace Umbraco.Tests.Services
// Act
contentService.DeleteOfType(contentType.Id);
var rootContent = contentService.GetRootContent();
- var contents = contentService.GetByType(contentType.Id);
+ var contents = contentService.GetPagedOfType(contentType.Id, 0, int.MaxValue, out var _, null);
// Assert
Assert.That(rootContent.Any(), Is.False);
@@ -1785,7 +1765,13 @@ namespace Umbraco.Tests.Services
contentService.Save(subsubpage, 0);
var content = contentService.GetById(NodeDto.NodeIdSeed + 2);
- var descendants = contentService.GetDescendants(content).ToList();
+ const int pageSize = 500;
+ var page = 0;
+ var total = long.MaxValue;
+ var descendants = new List();
+ while(page * pageSize < total)
+ descendants.AddRange(contentService.GetPagedDescendants(content.Id, page++, pageSize, out total));
+
Assert.AreNotEqual(-20, content.ParentId);
Assert.IsFalse(content.Trashed);
Assert.AreEqual(3, descendants.Count);
@@ -1793,7 +1779,11 @@ namespace Umbraco.Tests.Services
Assert.IsFalse(descendants.Any(x => x.Trashed));
contentService.MoveToRecycleBin(content, 0);
- descendants = contentService.GetDescendants(content).ToList();
+
+ descendants.Clear();
+ page = 0;
+ while (page * pageSize < total)
+ descendants.AddRange(contentService.GetPagedDescendants(content.Id, page++, pageSize, out total));
Assert.AreEqual(-20, content.ParentId);
Assert.IsTrue(content.Trashed);
@@ -1802,7 +1792,7 @@ namespace Umbraco.Tests.Services
Assert.True(descendants.All(x => x.Trashed));
contentService.EmptyRecycleBin();
- var trashed = contentService.GetContentInRecycleBin();
+ var trashed = contentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList();
Assert.IsEmpty(trashed);
}
@@ -1814,7 +1804,7 @@ namespace Umbraco.Tests.Services
// Act
contentService.EmptyRecycleBin();
- var contents = contentService.GetContentInRecycleBin();
+ var contents = contentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList();
// Assert
Assert.That(contents.Any(), Is.False);
@@ -1883,8 +1873,13 @@ namespace Umbraco.Tests.Services
ServiceContext.ContentService.Save(childPage3);
//Verify that the children have the inherited permissions
- var descendants = ServiceContext.ContentService.GetDescendants(parentPage).ToArray();
- Assert.AreEqual(3, descendants.Length);
+ var descendants = new List();
+ const int pageSize = 500;
+ var page = 0;
+ var total = long.MaxValue;
+ while(page * pageSize < total)
+ descendants.AddRange(ServiceContext.ContentService.GetPagedDescendants(parentPage.Id, page++, pageSize, out total));
+ Assert.AreEqual(3, descendants.Count);
foreach (var descendant in descendants)
{
@@ -1902,8 +1897,11 @@ namespace Umbraco.Tests.Services
//Now copy, what should happen is the child pages will now have permissions inherited from the new parent
var copy = ServiceContext.ContentService.Copy(childPage1, parentPage2.Id, false, true);
- descendants = ServiceContext.ContentService.GetDescendants(parentPage2).ToArray();
- Assert.AreEqual(3, descendants.Length);
+ descendants.Clear();
+ page = 0;
+ while (page * pageSize < total)
+ descendants.AddRange(ServiceContext.ContentService.GetPagedDescendants(parentPage2.Id, page++, pageSize, out total));
+ Assert.AreEqual(3, descendants.Count);
foreach (var descendant in descendants)
{
@@ -1984,7 +1982,7 @@ namespace Umbraco.Tests.Services
// Act
ServiceContext.ContentService.MoveToRecycleBin(content1);
ServiceContext.ContentService.EmptyRecycleBin();
- var contents = ServiceContext.ContentService.GetContentInRecycleBin();
+ var contents = ServiceContext.ContentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList();
// Assert
Assert.That(contents.Any(), Is.False);
@@ -2035,7 +2033,7 @@ namespace Umbraco.Tests.Services
var contentService = ServiceContext.ContentService;
var temp = contentService.GetById(NodeDto.NodeIdSeed + 2);
Assert.AreEqual("Home", temp.Name);
- Assert.AreEqual(2, temp.Children(contentService).Count());
+ Assert.AreEqual(2, contentService.CountChildren(temp.Id));
// Act
var copy = contentService.Copy(temp, temp.ParentId, false, true, 0);
@@ -2045,10 +2043,10 @@ namespace Umbraco.Tests.Services
Assert.That(copy, Is.Not.Null);
Assert.That(copy.Id, Is.Not.EqualTo(content.Id));
Assert.AreNotSame(content, copy);
- Assert.AreEqual(2, copy.Children(contentService).Count());
+ Assert.AreEqual(2, contentService.CountChildren(copy.Id));
var child = contentService.GetById(NodeDto.NodeIdSeed + 3);
- var childCopy = copy.Children(contentService).First();
+ var childCopy = contentService.GetPagedChildren(copy.Id, 0, 500, out var total).First();
Assert.AreEqual(childCopy.Name, child.Name);
Assert.AreNotEqual(childCopy.Id, child.Id);
Assert.AreNotEqual(childCopy.Key, child.Key);
@@ -2061,7 +2059,7 @@ namespace Umbraco.Tests.Services
var contentService = ServiceContext.ContentService;
var temp = contentService.GetById(NodeDto.NodeIdSeed + 2);
Assert.AreEqual("Home", temp.Name);
- Assert.AreEqual(2, temp.Children(contentService).Count());
+ Assert.AreEqual(2, contentService.CountChildren(temp.Id));
// Act
var copy = contentService.Copy(temp, temp.ParentId, false, false, 0);
@@ -2071,7 +2069,7 @@ namespace Umbraco.Tests.Services
Assert.That(copy, Is.Not.Null);
Assert.That(copy.Id, Is.Not.EqualTo(content.Id));
Assert.AreNotSame(content, copy);
- Assert.AreEqual(0, copy.Children(contentService).Count());
+ Assert.AreEqual(0, contentService.CountChildren(copy.Id));
}
[Test]
@@ -2780,7 +2778,7 @@ namespace Umbraco.Tests.Services
{
var languageService = ServiceContext.LocalizationService;
- var langUk = new Language("en-UK") { IsDefault = true };
+ var langUk = new Language("en-GB") { IsDefault = true };
var langFr = new Language("fr-FR");
languageService.Save(langFr);
@@ -2815,7 +2813,7 @@ namespace Umbraco.Tests.Services
{
var languageService = ServiceContext.LocalizationService;
- var langUk = new Language("en-UK") { IsDefault = true };
+ var langUk = new Language("en-GB") { IsDefault = true };
var langFr = new Language("fr-FR");
languageService.Save(langFr);
@@ -2852,7 +2850,7 @@ namespace Umbraco.Tests.Services
{
var languageService = ServiceContext.LocalizationService;
- var langUk = new Language("en-UK") { IsDefault = true };
+ var langUk = new Language("en-GB") { IsDefault = true };
var langFr = new Language("fr-FR");
var langDa = new Language("da-DK");
@@ -2944,7 +2942,7 @@ namespace Umbraco.Tests.Services
private void WriteList(List list)
{
foreach (var content in list)
- Console.WriteLine("[{0}] {1} {2} {3} {4}", content.Id, content.Name, content.GetCultureName("en-UK"), content.GetCultureName("fr-FR"), content.GetCultureName("da-DK"));
+ Console.WriteLine("[{0}] {1} {2} {3} {4}", content.Id, content.Name, content.GetCultureName("en-GB"), content.GetCultureName("fr-FR"), content.GetCultureName("da-DK"));
Console.WriteLine("-");
}
@@ -2956,7 +2954,7 @@ namespace Umbraco.Tests.Services
//var langFr = new Language("fr-FR") { IsDefaultVariantLanguage = true };
var langXx = new Language("pt-PT") { IsDefault = true };
var langFr = new Language("fr-FR");
- var langUk = new Language("en-UK");
+ var langUk = new Language("en-GB");
var langDe = new Language("de-DE");
languageService.Save(langFr);
diff --git a/src/Umbraco.Tests/Services/MediaServiceTests.cs b/src/Umbraco.Tests/Services/MediaServiceTests.cs
index 68fd2c3e11..b9e1fee0db 100644
--- a/src/Umbraco.Tests/Services/MediaServiceTests.cs
+++ b/src/Umbraco.Tests/Services/MediaServiceTests.cs
@@ -69,11 +69,15 @@ namespace Umbraco.Tests.Services
}
long total;
- var result = ServiceContext.MediaService.GetPagedChildren(-1, 0, 11, out total, "SortOrder", Direction.Ascending, true, null, new[] { mediaType1.Id, mediaType2.Id });
+ var result = ServiceContext.MediaService.GetPagedChildren(-1, 0, 11, out total,
+ SqlContext.Query().Where(x => new[] { mediaType1.Id, mediaType2.Id }.Contains(x.ContentTypeId)),
+ Ordering.By("SortOrder", Direction.Ascending));
Assert.AreEqual(11, result.Count());
Assert.AreEqual(20, total);
- result = ServiceContext.MediaService.GetPagedChildren(-1, 1, 11, out total, "SortOrder", Direction.Ascending, true, null, new[] { mediaType1.Id, mediaType2.Id });
+ result = ServiceContext.MediaService.GetPagedChildren(-1, 1, 11, out total,
+ SqlContext.Query().Where(x => new[] { mediaType1.Id, mediaType2.Id }.Contains(x.ContentTypeId)),
+ Ordering.By("SortOrder", Direction.Ascending));
Assert.AreEqual(9, result.Count());
Assert.AreEqual(20, total);
}
diff --git a/src/Umbraco.Tests/Services/PerformanceTests.cs b/src/Umbraco.Tests/Services/PerformanceTests.cs
index 9b0117c266..900a466a1d 100644
--- a/src/Umbraco.Tests/Services/PerformanceTests.cs
+++ b/src/Umbraco.Tests/Services/PerformanceTests.cs
@@ -108,40 +108,6 @@ namespace Umbraco.Tests.Services
}
}
- [Test]
- public void Get_All_Published_Content_Of_Type()
- {
- var result = PrimeDbWithLotsOfContent();
- var contentSvc = (ContentService)ServiceContext.ContentService;
-
- var countOfPublished = result.Count(x => x.Published);
- var contentTypeId = result.First().ContentTypeId;
-
- var proflog = GetTestProfilingLogger();
- using (proflog.DebugDuration("Getting published content of type normally"))
- {
- //do this 10x!
- for (var i = 0; i < 10; i++)
- {
-
- //get all content items that are published of this type
- var published = contentSvc.GetByType(contentTypeId).Where(content => content.Published);
- Assert.AreEqual(countOfPublished, published.Count(x => x.ContentTypeId == contentTypeId));
- }
- }
-
- using (proflog.DebugDuration("Getting published content of type optimized"))
- {
-
- //do this 10x!
- for (var i = 0; i < 10; i++)
- {
- //get all content items that are published of this type
- var published = contentSvc.GetPublishedContentOfContentType(contentTypeId);
- Assert.AreEqual(countOfPublished, published.Count(x => x.ContentTypeId == contentTypeId));
- }
- }
- }
[Test]
public void Truncate_Insert_Vs_Update_Insert()
diff --git a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs
index dedf04488c..8b57e10849 100644
--- a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs
+++ b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs
@@ -71,11 +71,7 @@ namespace Umbraco.Tests.UmbracoExamine
contentService = Mock.Of(
x => x.GetPagedDescendants(
- It.IsAny(), It.IsAny(), It.IsAny(), out longTotalRecs, It.IsAny(), It.IsAny(), It.IsAny())
- ==
- allRecs
- && x.GetPagedDescendants(
- It.IsAny(), It.IsAny(), It.IsAny(), out longTotalRecs, It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>())
+ It.IsAny(), It.IsAny(), It.IsAny(), out longTotalRecs, It.IsAny>(), It.IsAny())
==
allRecs);
}
@@ -116,12 +112,7 @@ namespace Umbraco.Tests.UmbracoExamine
mediaServiceMock
.Setup(x => x.GetPagedDescendants(
- It.IsAny(), It.IsAny(), It.IsAny(), out totalRecs, It.IsAny(), It.IsAny(), It.IsAny())
- ).Returns(() => allRecs);
-
- mediaServiceMock
- .Setup(x => x.GetPagedDescendants(
- It.IsAny(), It.IsAny(), It.IsAny(), out totalRecs, It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>())
+ It.IsAny(), It.IsAny(), It.IsAny(), out totalRecs, It.IsAny>(), It.IsAny())
).Returns(() => allRecs);
//mediaServiceMock.Setup(service => service.GetPagedXmlEntries(It.IsAny(), It.IsAny(), It.IsAny(), out longTotalRecs))
diff --git a/src/Umbraco.Tests/UmbracoExamine/SearchTests.cs b/src/Umbraco.Tests/UmbracoExamine/SearchTests.cs
index 2d440b8453..768d1c735c 100644
--- a/src/Umbraco.Tests/UmbracoExamine/SearchTests.cs
+++ b/src/Umbraco.Tests/UmbracoExamine/SearchTests.cs
@@ -49,7 +49,7 @@ namespace Umbraco.Tests.UmbracoExamine
.ToArray();
var contentService = Mock.Of(
x => x.GetPagedDescendants(
- It.IsAny(), It.IsAny(), It.IsAny(), out totalRecs, It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>())
+ It.IsAny(), It.IsAny(), It.IsAny(), out totalRecs, It.IsAny>(), It.IsAny())
==
allRecs);
diff --git a/src/Umbraco.Web.UI/Umbraco/dialogs/ChangeDocType.aspx.cs b/src/Umbraco.Web.UI/Umbraco/dialogs/ChangeDocType.aspx.cs
index 2297ea1aa7..8111410edd 100644
--- a/src/Umbraco.Web.UI/Umbraco/dialogs/ChangeDocType.aspx.cs
+++ b/src/Umbraco.Web.UI/Umbraco/dialogs/ChangeDocType.aspx.cs
@@ -113,7 +113,8 @@ namespace Umbraco.Web.UI.Umbraco.Dialogs
private IEnumerable RemoveInvalidByChildrenDocumentTypesFromAlternatives(IEnumerable documentTypes)
{
- var docTypeIdsOfChildren = _content.Children(Services.ContentService)
+ //fixme Should do proper paging here ... when this is refactored we will
+ var docTypeIdsOfChildren = Services.ContentService.GetPagedChildren(_content.Id, 0, int.MaxValue, out var total)
.Select(x => x.ContentType.Id)
.Distinct()
.ToList();
diff --git a/src/Umbraco.Web/CompositionExtensions.cs b/src/Umbraco.Web/CompositionExtensions.cs
index 38b0be3103..fe2ea4b8a7 100644
--- a/src/Umbraco.Web/CompositionExtensions.cs
+++ b/src/Umbraco.Web/CompositionExtensions.cs
@@ -11,6 +11,7 @@ using Umbraco.Web.Mvc;
using Umbraco.Web.PublishedCache;
using Umbraco.Web.Routing;
using Umbraco.Web.ContentApps;
+using Umbraco.Web.Features;
// the namespace here is intentional - although defined in Umbraco.Web assembly,
// this class should be visible when using Umbraco.Core.Components, alongside
@@ -58,6 +59,9 @@ namespace Umbraco.Core.Components
internal static EditorValidatorCollectionBuilder EditorValidators(this Composition composition)
=> composition.Container.GetInstance();
+ public static UmbracoFeatures Features(this Composition composition)
+ => composition.Container.GetInstance();
+
///
/// Gets the filtered controller factories collection builder.
///
diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs
index 53e2593fef..03bfc78204 100644
--- a/src/Umbraco.Web/Editors/ContentController.cs
+++ b/src/Umbraco.Web/Editors/ContentController.cs
@@ -457,7 +457,7 @@ namespace Umbraco.Web.Editors
public PagedResult> GetChildren(
int id,
string includeProperties,
- int pageNumber = 0, //TODO: This should be '1' as it's not the index
+ int pageNumber = 0,
int pageSize = 0,
string orderBy = "SortOrder",
Direction orderDirection = Direction.Ascending,
@@ -484,7 +484,8 @@ namespace Umbraco.Web.Editors
}
else
{
- children = Services.ContentService.GetChildren(id).ToList();
+ //better to not use this without paging where possible, currently only the sort dialog does
+ children = Services.ContentService.GetPagedChildren(id, 0, int.MaxValue, out var total).ToList();
totalChildren = children.Count;
}
@@ -1318,7 +1319,7 @@ namespace Umbraco.Web.Editors
xnames.Add(xcontent.Name);
if (xcontent.ParentId < -1)
xnames.Add("Recycle Bin");
- xcontent = xcontent.Parent(Services.ContentService);
+ xcontent = Services.ContentService.GetParent(xcontent);
}
xnames.Reverse();
domainModel.Other = "/" + string.Join("/", xnames);
diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs
index dc744ea361..f61cbc5952 100644
--- a/src/Umbraco.Web/Editors/MediaController.cs
+++ b/src/Umbraco.Web/Editors/MediaController.cs
@@ -209,7 +209,10 @@ namespace Umbraco.Web.Editors
}
long total;
- var children = Services.MediaService.GetPagedChildren(id, pageNumber - 1, pageSize, out total, "Name", Direction.Ascending, true, null, folderTypes.ToArray());
+ var children = Services.MediaService.GetPagedChildren(id, pageNumber - 1, pageSize, out total,
+ //lookup these content types
+ SqlContext.Query().Where(x => folderTypes.Contains(x.ContentTypeId)),
+ Ordering.By("Name", Direction.Ascending));
return new PagedResult>(total, pageNumber, pageSize)
{
@@ -271,7 +274,7 @@ namespace Umbraco.Web.Editors
// else proceed as usual
long totalChildren;
- IMedia[] children;
+ List children;
if (pageNumber > 0 && pageSize > 0)
{
IQuery queryFilter = null;
@@ -286,13 +289,14 @@ namespace Umbraco.Web.Editors
.GetPagedChildren(
id, (pageNumber - 1), pageSize,
out totalChildren,
- orderBy, orderDirection, orderBySystemField,
- queryFilter).ToArray();
+ queryFilter,
+ Ordering.By(orderBy, orderDirection, isCustomField: !orderBySystemField)).ToList();
}
else
{
- children = Services.MediaService.GetChildren(id).ToArray();
- totalChildren = children.Length;
+ //better to not use this without paging where possible, currently only the sort dialog does
+ children = Services.MediaService.GetPagedChildren(id, 0, int.MaxValue, out var total).ToList();
+ totalChildren = children.Count;
}
if (totalChildren == 0)
@@ -663,7 +667,8 @@ namespace Umbraco.Web.Editors
" returned null");
//look for matching folder
- folderMediaItem = mediaRoot.Children(Services.MediaService).FirstOrDefault(x => x.Name == folderName && x.ContentType.Alias == Constants.Conventions.MediaTypes.Folder);
+ folderMediaItem = FindInChildren(mediaRoot.Id, folderName, Constants.Conventions.MediaTypes.Folder);
+
if (folderMediaItem == null)
{
//if null, create a folder
@@ -753,6 +758,21 @@ namespace Umbraco.Web.Editors
return Request.CreateResponse(HttpStatusCode.OK, tempFiles);
}
+ private IMedia FindInChildren(int mediaId, string nameToFind, string contentTypeAlias)
+ {
+ const int pageSize = 500;
+ var page = 0;
+ var total = long.MaxValue;
+ while (page * pageSize < total)
+ {
+ var children = Services.MediaService.GetPagedChildren(mediaId, page, pageSize, out total,
+ SqlContext.Query().Where(x => x.Name == nameToFind));
+ foreach (var c in children)
+ return c; //return first one if any are found
+ }
+ return null;
+ }
+
///
/// Given a parent id which could be a GUID, UDI or an INT, this will resolve the INT
///
diff --git a/src/Umbraco.Web/Routing/UrlProviderExtensions.cs b/src/Umbraco.Web/Routing/UrlProviderExtensions.cs
index 2be0dce096..14b9c0a465 100644
--- a/src/Umbraco.Web/Routing/UrlProviderExtensions.cs
+++ b/src/Umbraco.Web/Routing/UrlProviderExtensions.cs
@@ -129,7 +129,7 @@ namespace Umbraco.Web.Routing
var parent = content;
do
{
- parent = parent.ParentId > 0 ? parent.Parent(contentService) : null;
+ parent = parent.ParentId > 0 ? contentService.GetParent(parent) : null;
}
while (parent != null && parent.Published && (!parent.ContentType.VariesByCulture() || parent.IsCulturePublished(culture)));
diff --git a/src/Umbraco.Web/Search/ExamineComponent.cs b/src/Umbraco.Web/Search/ExamineComponent.cs
index ff7d0c8dc4..7a036ef712 100644
--- a/src/Umbraco.Web/Search/ExamineComponent.cs
+++ b/src/Umbraco.Web/Search/ExamineComponent.cs
@@ -26,6 +26,7 @@ using Umbraco.Web.Cache;
using Umbraco.Web.Composing;
using Umbraco.Web.PropertyEditors;
using Umbraco.Examine;
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Web.Search
{
@@ -102,13 +103,10 @@ namespace Umbraco.Web.Search
// bind to distributed cache events - this ensures that this logic occurs on ALL servers
// that are taking part in a load balanced environment.
ContentCacheRefresher.CacheUpdated += ContentCacheRefresherUpdated;
+ ContentTypeCacheRefresher.CacheUpdated += ContentTypeCacheRefresherUpdated; ;
MediaCacheRefresher.CacheUpdated += MediaCacheRefresherUpdated;
MemberCacheRefresher.CacheUpdated += MemberCacheRefresherUpdated;
- // fixme - content type?
- // events handling removed in ef013f9d3b945d0a48a306ff1afbd49c10c3fff8
- // because, could not make sense of it?
-
EnsureUnlocked(profilingLogger.Logger, examineManager);
RebuildIndexesOnStartup(profilingLogger.Logger);
@@ -307,16 +305,191 @@ namespace Umbraco.Web.Search
// branch
if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshBranch))
{
- var descendants = mediaService.GetDescendants(media);
- foreach (var descendant in descendants)
+ const int pageSize = 500;
+ var page = 0;
+ var total = long.MaxValue;
+ while (page * pageSize < total)
{
- ReIndexForMedia(descendant, descendant.Trashed == false);
+ var descendants = mediaService.GetPagedDescendants(media.Id, page++, pageSize, out total);
+ foreach (var descendant in descendants)
+ {
+ ReIndexForMedia(descendant, descendant.Trashed == false);
+ }
}
}
}
}
}
+ ///
+ /// Updates indexes based on content type changes
+ ///
+ ///
+ ///
+ private void ContentTypeCacheRefresherUpdated(ContentTypeCacheRefresher sender, CacheRefresherEventArgs args)
+ {
+ if (Suspendable.ExamineEvents.CanIndex == false)
+ return;
+
+ if (args.MessageType != MessageType.RefreshByPayload)
+ throw new NotSupportedException();
+
+ var changedIds = new Dictionary removedIds, List refreshedIds, List otherIds)>();
+
+ foreach (var payload in (ContentTypeCacheRefresher.JsonPayload[])args.MessageObject)
+ {
+ if (!changedIds.TryGetValue(payload.ItemType, out var idLists))
+ {
+ idLists = (removedIds: new List(), refreshedIds: new List(), otherIds: new List());
+ changedIds.Add(payload.ItemType, idLists);
+ }
+
+ if (payload.ChangeTypes.HasType(ContentTypeChangeTypes.Remove))
+ idLists.removedIds.Add(payload.Id);
+ else if (payload.ChangeTypes.HasType(ContentTypeChangeTypes.RefreshMain))
+ idLists.refreshedIds.Add(payload.Id);
+ else if (payload.ChangeTypes.HasType(ContentTypeChangeTypes.RefreshOther))
+ idLists.otherIds.Add(payload.Id);
+ }
+
+ const int pageSize = 500;
+
+ foreach(var ci in changedIds)
+ {
+ if (ci.Value.refreshedIds.Count > 0 || ci.Value.otherIds.Count > 0)
+ {
+ switch(ci.Key)
+ {
+ case var itemType when itemType == typeof(IContentType).Name:
+ RefreshContentOfContentTypes(ci.Value.refreshedIds.Concat(ci.Value.otherIds).Distinct().ToArray());
+ break;
+ case var itemType when itemType == typeof(IMediaType).Name:
+ RefreshMediaOfMediaTypes(ci.Value.refreshedIds.Concat(ci.Value.otherIds).Distinct().ToArray());
+ break;
+ case var itemType when itemType == typeof(IMemberType).Name:
+ RefreshMemberOfMemberTypes(ci.Value.refreshedIds.Concat(ci.Value.otherIds).Distinct().ToArray());
+ break;
+ }
+ }
+
+ //Delete all content of this content/media/member type that is in any content indexer by looking up matched examine docs
+ foreach (var id in ci.Value.removedIds)
+ {
+ foreach (var index in _examineManager.IndexProviders.Values.OfType())
+ {
+ var searcher = index.GetSearcher();
+
+ var page = 0;
+ var total = long.MaxValue;
+ while (page * pageSize < total)
+ {
+ //paging with examine, see https://shazwazza.com/post/paging-with-examine/
+ var results = searcher.Search(
+ searcher.CreateCriteria().Field("nodeType", id).Compile(),
+ maxResults: pageSize * (page + 1));
+ total = results.TotalItemCount;
+ var paged = results.Skip(page * pageSize);
+
+ foreach (var item in paged)
+ if (int.TryParse(item.Id, out var contentId))
+ DeleteIndexForEntity(contentId, false);
+ }
+ }
+ }
+ }
+ }
+
+ private void RefreshMemberOfMemberTypes(int[] memberTypeIds)
+ {
+ const int pageSize = 500;
+
+ var memberTypes = _services.MemberTypeService.GetAll(memberTypeIds);
+ foreach(var memberType in memberTypes)
+ {
+ var page = 0;
+ var total = long.MaxValue;
+ while (page * pageSize < total)
+ {
+ var memberToRefresh = _services.MemberService.GetAll(
+ page++, pageSize, out total, "LoginName", Direction.Ascending,
+ memberType.Alias);
+
+ foreach (var c in memberToRefresh)
+ {
+ ReIndexForMember(c);
+ }
+ }
+ }
+ }
+
+ private void RefreshMediaOfMediaTypes(int[] mediaTypeIds)
+ {
+ const int pageSize = 500;
+ var page = 0;
+ var total = long.MaxValue;
+ while (page * pageSize < total)
+ {
+ var mediaToRefresh = _services.MediaService.GetPagedOfTypes(
+ //Re-index all content of these types
+ mediaTypeIds,
+ page++, pageSize, out total, null,
+ Ordering.By("Path", Direction.Ascending));
+
+ foreach (var c in mediaToRefresh)
+ {
+ ReIndexForMedia(c, c.Trashed == false);
+ }
+ }
+ }
+
+ private void RefreshContentOfContentTypes(int[] contentTypeIds)
+ {
+ const int pageSize = 500;
+ var page = 0;
+ var total = long.MaxValue;
+ while (page * pageSize < total)
+ {
+ var contentToRefresh = _services.ContentService.GetPagedOfTypes(
+ //Re-index all content of these types
+ contentTypeIds,
+ page++, pageSize, out total, null,
+ //order by shallowest to deepest, this allows us to check it's published state without checking every item
+ Ordering.By("Path", Direction.Ascending));
+
+ //track which Ids have their paths are published
+ var publishChecked = new Dictionary();
+
+ foreach (var c in contentToRefresh)
+ {
+ IContent published = null;
+ if (c.Published)
+ {
+ if (publishChecked.TryGetValue(c.ParentId, out var isPublished))
+ {
+ //if the parent's published path has already been verified then this is published
+ if (isPublished)
+ published = c;
+ }
+ else
+ {
+ //nothing by parent id, so query the service and cache the result for the next child to check against
+ isPublished = _services.ContentService.IsPathPublished(c);
+ publishChecked[c.Id] = isPublished;
+ if (isPublished)
+ published = c;
+ }
+ }
+
+ ReIndexForContent(c, published);
+ }
+ }
+ }
+
+ ///
+ /// Updates indexes based on content changes
+ ///
+ ///
+ ///
private void ContentCacheRefresherUpdated(ContentCacheRefresher sender, CacheRefresherEventArgs args)
{
if (Suspendable.ExamineEvents.CanIndex == false)
@@ -340,6 +513,8 @@ namespace Umbraco.Web.Search
// ExamineEvents does not support RefreshAll
// just ignore that payload
// so what?!
+
+ //fixme: Rebuild the index at this point?
}
else // RefreshNode or RefreshBranch (maybe trashed)
{
@@ -355,7 +530,7 @@ namespace Umbraco.Web.Search
}
IContent published = null;
- if (content.Published && ((ContentService)contentService).IsPathPublished(content))
+ if (content.Published && contentService.IsPathPublished(content))
published = content;
// just that content
@@ -365,19 +540,28 @@ namespace Umbraco.Web.Search
if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshBranch))
{
var masked = published == null ? null : new List();
- var descendants = contentService.GetDescendants(content);
- foreach (var descendant in descendants)
+ const int pageSize = 500;
+ var page = 0;
+ var total = long.MaxValue;
+ while(page * pageSize < total)
{
- published = null;
- if (masked != null) // else everything is masked
- {
- if (masked.Contains(descendant.ParentId) || !descendant.Published)
- masked.Add(descendant.Id);
- else
- published = descendant;
- }
+ var descendants = contentService.GetPagedDescendants(content.Id, page++, pageSize, out total,
+ //order by shallowest to deepest, this allows us to check it's published state without checking every item
+ ordering: Ordering.By("Path", Direction.Ascending));
- ReIndexForContent(descendant, published);
+ foreach (var descendant in descendants)
+ {
+ published = null;
+ if (masked != null) // else everything is masked
+ {
+ if (masked.Contains(descendant.ParentId) || !descendant.Published)
+ masked.Add(descendant.Id);
+ else
+ published = descendant;
+ }
+
+ ReIndexForContent(descendant, published);
+ }
}
}
}
diff --git a/src/Umbraco.Web/Trees/ContentBlueprintTreeController.cs b/src/Umbraco.Web/Trees/ContentBlueprintTreeController.cs
index 364c9c391f..365308a8f2 100644
--- a/src/Umbraco.Web/Trees/ContentBlueprintTreeController.cs
+++ b/src/Umbraco.Web/Trees/ContentBlueprintTreeController.cs
@@ -33,6 +33,9 @@ namespace Umbraco.Web.Trees
//this will load in a custom UI instead of the dashboard for the root node
root.RoutePath = $"{Constants.Applications.Settings}/{Constants.Trees.ContentBlueprints}/intro";
+ //check if there are any content blueprints
+ root.HasChildren = Services.ContentService.GetBlueprintsForContentTypes().Any();
+
return root;
}
protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
diff --git a/src/Umbraco.Web/Trees/FileSystemTreeController.cs b/src/Umbraco.Web/Trees/FileSystemTreeController.cs
index f1e53ed5d4..9babb656fe 100644
--- a/src/Umbraco.Web/Trees/FileSystemTreeController.cs
+++ b/src/Umbraco.Web/Trees/FileSystemTreeController.cs
@@ -75,6 +75,14 @@ namespace Umbraco.Web.Trees
return nodes;
}
+ protected override TreeNode CreateRootNode(FormDataCollection queryStrings)
+ {
+ var root = base.CreateRootNode(queryStrings);
+ //check if there are any children
+ root.HasChildren = GetTreeNodes(Constants.System.Root.ToInvariantString(), queryStrings).Any();
+ return root;
+ }
+
protected virtual MenuItemCollection GetMenuForRootNode(FormDataCollection queryStrings)
{
var menu = new MenuItemCollection();
diff --git a/src/Umbraco.Web/Trees/MemberTypeTreeController.cs b/src/Umbraco.Web/Trees/MemberTypeTreeController.cs
index 77eb6e0b24..7bf04010f2 100644
--- a/src/Umbraco.Web/Trees/MemberTypeTreeController.cs
+++ b/src/Umbraco.Web/Trees/MemberTypeTreeController.cs
@@ -7,11 +7,18 @@ using Umbraco.Web.WebApi.Filters;
namespace Umbraco.Web.Trees
{
- [CoreTree(TreeGroup =Constants.Trees.Groups.Settings)]
+ [CoreTree(TreeGroup = Constants.Trees.Groups.Settings)]
[UmbracoTreeAuthorize(Constants.Trees.MemberTypes)]
[Tree(Constants.Applications.Settings, Constants.Trees.MemberTypes, null, sortOrder: 2)]
public class MemberTypeTreeController : MemberTypeAndGroupTreeControllerBase
{
+ protected override TreeNode CreateRootNode(FormDataCollection queryStrings)
+ {
+ var root = base.CreateRootNode(queryStrings);
+ //check if there are any member types
+ root.HasChildren = Services.MemberTypeService.GetAll().Any();
+ return root;
+ }
protected override IEnumerable GetTreeNodesFromService(string id, FormDataCollection queryStrings)
{
return Services.MemberTypeService.GetAll()
diff --git a/src/Umbraco.Web/Trees/TemplatesTreeController.cs b/src/Umbraco.Web/Trees/TemplatesTreeController.cs
index 2339d92d96..3fc005d670 100644
--- a/src/Umbraco.Web/Trees/TemplatesTreeController.cs
+++ b/src/Umbraco.Web/Trees/TemplatesTreeController.cs
@@ -25,6 +25,14 @@ namespace Umbraco.Web.Trees
[CoreTree(TreeGroup = Constants.Trees.Groups.Templating)]
public class TemplatesTreeController : TreeController, ISearchableTree
{
+ protected override TreeNode CreateRootNode(FormDataCollection queryStrings)
+ {
+ var root = base.CreateRootNode(queryStrings);
+ //check if there are any templates
+ root.HasChildren = Services.FileService.GetTemplates(-1).Any();
+ return root;
+ }
+
///
/// The method called to render the contents of the tree structure
///