diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/References/AreReferencedDocumentController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/References/AreReferencedDocumentController.cs
index b73aa9ac94..ed593e9c9e 100644
--- a/src/Umbraco.Cms.Api.Management/Controllers/Document/References/AreReferencedDocumentController.cs
+++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/References/AreReferencedDocumentController.cs
@@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
using Umbraco.Cms.Api.Management.ViewModels;
+using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
@@ -22,7 +23,7 @@ public class AreReferencedDocumentController : DocumentControllerBase
}
///
- /// Gets a page list of the items used in any kind of relation from selected keys.
+ /// Gets a paged list of the items used in any kind of relation from selected keys.
///
///
/// Used when bulk deleting content/media and bulk unpublishing content (delete and unpublish on List view).
@@ -37,11 +38,11 @@ public class AreReferencedDocumentController : DocumentControllerBase
int skip = 0,
int take = 20)
{
- PagedModel distinctByKeyItemsWithReferencedRelations = await _trackedReferencesSkipTakeService.GetPagedItemsWithRelationsAsync(ids, skip, take, true);
+ PagedModel distinctByKeyItemsWithReferencedRelations = await _trackedReferencesSkipTakeService.GetPagedKeysWithDependentReferencesAsync(ids, Constants.ObjectTypes.Document, skip, take);
var pagedViewModel = new PagedViewModel
{
Total = distinctByKeyItemsWithReferencedRelations.Total,
- Items = _umbracoMapper.MapEnumerable(distinctByKeyItemsWithReferencedRelations.Items),
+ Items = _umbracoMapper.MapEnumerable(distinctByKeyItemsWithReferencedRelations.Items),
};
return await Task.FromResult(pagedViewModel);
diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/References/ReferencedByDocumentController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/References/ReferencedByDocumentController.cs
index 0e7e05a29f..a818e70af8 100644
--- a/src/Umbraco.Cms.Api.Management/Controllers/Document/References/ReferencedByDocumentController.cs
+++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/References/ReferencedByDocumentController.cs
@@ -22,7 +22,7 @@ public class ReferencedByDocumentController : DocumentControllerBase
}
///
- /// Gets a page list of tracked references for the current item, so you can see where an item is being used.
+ /// Gets a paged list of tracked references for the current item, so you can see where an item is being used.
///
///
/// Used by info tabs on content, media etc. and for the delete and unpublish of single items.
diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/References/ReferencedDescendantsDocumentController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/References/ReferencedDescendantsDocumentController.cs
index 7ee7bae77f..4b931632e1 100644
--- a/src/Umbraco.Cms.Api.Management/Controllers/Document/References/ReferencedDescendantsDocumentController.cs
+++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/References/ReferencedDescendantsDocumentController.cs
@@ -22,7 +22,7 @@ public class ReferencedDescendantsDocumentController : DocumentControllerBase
}
///
- /// Gets a page list of the child nodes of the current item used in any kind of relation.
+ /// Gets a paged list of the descendant nodes of the current item used in any kind of relation.
///
///
/// Used when deleting and unpublishing a single item to check if this item has any descending items that are in any
diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Media/References/AreReferencedMediaController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Media/References/AreReferencedMediaController.cs
index 4ec013a0e7..89e0c2d1ba 100644
--- a/src/Umbraco.Cms.Api.Management/Controllers/Media/References/AreReferencedMediaController.cs
+++ b/src/Umbraco.Cms.Api.Management/Controllers/Media/References/AreReferencedMediaController.cs
@@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
using Umbraco.Cms.Api.Management.ViewModels;
+using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
@@ -38,11 +39,11 @@ public class AreReferencedMediaController : MediaControllerBase
int skip = 0,
int take = 20)
{
- PagedModel distinctByKeyItemsWithReferencedRelations = await _trackedReferencesSkipTakeService.GetPagedItemsWithRelationsAsync(ids, skip, take, true);
+ PagedModel distinctByKeyItemsWithReferencedRelations = await _trackedReferencesSkipTakeService.GetPagedKeysWithDependentReferencesAsync(ids, Constants.ObjectTypes.Media, skip, take);
var pagedViewModel = new PagedViewModel
{
Total = distinctByKeyItemsWithReferencedRelations.Total,
- Items = _umbracoMapper.MapEnumerable(distinctByKeyItemsWithReferencedRelations.Items),
+ Items = _umbracoMapper.MapEnumerable(distinctByKeyItemsWithReferencedRelations.Items),
};
return await Task.FromResult(pagedViewModel);
diff --git a/src/Umbraco.Cms.Api.Management/Mapping/TrackedReferences/TrackedReferenceViewModelsMapDefinition.cs b/src/Umbraco.Cms.Api.Management/Mapping/TrackedReferences/TrackedReferenceViewModelsMapDefinition.cs
index 5d53d120a2..6a4fe40c62 100644
--- a/src/Umbraco.Cms.Api.Management/Mapping/TrackedReferences/TrackedReferenceViewModelsMapDefinition.cs
+++ b/src/Umbraco.Cms.Api.Management/Mapping/TrackedReferences/TrackedReferenceViewModelsMapDefinition.cs
@@ -13,6 +13,7 @@ public class TrackedReferenceViewModelsMapDefinition : IMapDefinition
mapper.Define((source, context) => new MediaReferenceResponseModel(), Map);
mapper.Define((source, context) => new DefaultReferenceResponseModel(), Map);
mapper.Define((source, context) => new ReferenceByIdModel(), Map);
+ mapper.Define((source, context) => new ReferenceByIdModel(), Map);
}
// Umbraco.Code.MapAll
@@ -56,4 +57,10 @@ public class TrackedReferenceViewModelsMapDefinition : IMapDefinition
{
target.Id = source.NodeKey;
}
+
+ // Umbraco.Code.MapAll
+ private void Map(Guid source, ReferenceByIdModel target, MapperContext context)
+ {
+ target.Id = source;
+ }
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/ITrackedReferencesRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ITrackedReferencesRepository.cs
index 4442e5ecf2..01bff9f356 100644
--- a/src/Umbraco.Core/Persistence/Repositories/ITrackedReferencesRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/ITrackedReferencesRepository.cs
@@ -131,4 +131,14 @@ public interface ITrackedReferencesRepository
long take,
bool filterMustBeIsDependency,
out long totalRecords);
+
+ Task> GetPagedNodeKeysWithDependantReferencesAsync(
+ ISet keys,
+ Guid nodeObjectTypeId,
+ long skip,
+ long take)
+ {
+ IEnumerable pagedItems = GetPagedItemsWithRelations(keys, skip, take, true, out var total);
+ return Task.FromResult(new PagedModel(total, pagedItems.Select(i => i.NodeKey)));
+ }
}
diff --git a/src/Umbraco.Core/Services/ITrackedReferencesService.cs b/src/Umbraco.Core/Services/ITrackedReferencesService.cs
index 7cfcd1c117..c60156d31b 100644
--- a/src/Umbraco.Core/Services/ITrackedReferencesService.cs
+++ b/src/Umbraco.Core/Services/ITrackedReferencesService.cs
@@ -97,4 +97,10 @@ public interface ITrackedReferencesService
/// A paged result of objects.
Task> GetPagedItemsWithRelationsAsync(ISet keys, long skip, long take,
bool filterMustBeIsDependency);
+
+ Task> GetPagedKeysWithDependentReferencesAsync(ISet keys, Guid nodeObjectTypeId, long skip, long take)
+ {
+ PagedModel pagedItems = GetPagedItemsWithRelationsAsync(keys, skip, take, true).GetAwaiter().GetResult();
+ return Task.FromResult(new PagedModel(pagedItems.Total, pagedItems.Items.Select(i => i.NodeKey)));
+ }
}
diff --git a/src/Umbraco.Core/Services/TrackedReferencesService.cs b/src/Umbraco.Core/Services/TrackedReferencesService.cs
index 06b8fc5510..5d5d76f7f0 100644
--- a/src/Umbraco.Core/Services/TrackedReferencesService.cs
+++ b/src/Umbraco.Core/Services/TrackedReferencesService.cs
@@ -141,4 +141,10 @@ public class TrackedReferencesService : ITrackedReferencesService
return await Task.FromResult(pagedModel);
}
+
+ public async Task> GetPagedKeysWithDependentReferencesAsync(ISet keys, Guid objectTypeId, long skip, long take)
+ {
+ using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
+ return await _trackedReferencesRepository.GetPagedNodeKeysWithDependantReferencesAsync(keys, objectTypeId, skip, take);
+ }
}
diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TrackedReferencesRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TrackedReferencesRepository.cs
index 90e3fde207..2b7a43589c 100644
--- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TrackedReferencesRepository.cs
+++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TrackedReferencesRepository.cs
@@ -477,10 +477,49 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
return _umbracoMapper.MapEnumerable(pagedResult);
}
- public IEnumerable GetPagedDescendantsInReferences(
- Guid parentKey,
+ public async Task> GetPagedNodeKeysWithDependantReferencesAsync(
+ ISet keys,
+ Guid nodeObjectTypeId,
long skip,
- long take,
+ long take)
+ {
+ if (_scopeAccessor.AmbientScope is null)
+ {
+ throw new InvalidOperationException("Can not execute without a valid AmbientScope");
+ }
+
+ Sql? sql = _scopeAccessor.AmbientScope.Database.SqlContext.Sql()
+ .SelectDistinct(node => node.UniqueId)
+ .From()
+ .InnerJoin()
+ .On((node, relation) =>
+ node.NodeId == relation.ParentId || node.NodeId == relation.ParentId || node.NodeId == relation.ChildId)
+ .InnerJoin()
+ .On((relation, relationType) => relation.RelationType == relationType.Id && relationType.IsDependency)
+ .Where(
+ (node, relation, relationType)
+ => node.NodeObjectType == nodeObjectTypeId
+ && keys.Contains(node.UniqueId)
+ && (node.NodeId == relation.ChildId
+ || (relationType.Dual && relation.ParentId == node.NodeId)));
+
+ var totalRecords = _scopeAccessor.AmbientScope.Database.Count(sql);
+
+ // no need to process further if no records are found
+ if (totalRecords < 1)
+ {
+ return new PagedModel(totalRecords, Enumerable.Empty());
+ }
+
+ // Ordering is required for paging
+ sql = sql.OrderBy(node => node.UniqueId);
+
+ IEnumerable result = await _scopeAccessor.AmbientScope.Database.SkipTakeAsync(skip, take, sql);
+
+ return new PagedModel(totalRecords, result);
+ }
+
+ public IEnumerable GetPagedDescendantsInReferences(Guid parentKey, long skip, long take,
bool filterMustBeIsDependency,
out long totalRecords)
{