Optimize tracked references (#16996)
* Optimed sql for checking if a list documents is tracked by a reference * Remove unoptimzed method and update Media controller too * Revert spacing, formatting and unneeded code change This partially reverts commit d32b6acf4fa2f167e40b789e0cd02ce355a3a8ed. * Cleanup temporary renaming * Add default implementations * Fix merge issue --------- Co-authored-by: Bjarke Berg <mail@bergmania.dk>
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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<RelationItemModel> distinctByKeyItemsWithReferencedRelations = await _trackedReferencesSkipTakeService.GetPagedItemsWithRelationsAsync(ids, skip, take, true);
|
||||
PagedModel<Guid> distinctByKeyItemsWithReferencedRelations = await _trackedReferencesSkipTakeService.GetPagedKeysWithDependentReferencesAsync(ids, Constants.ObjectTypes.Document, skip, take);
|
||||
var pagedViewModel = new PagedViewModel<ReferenceByIdModel>
|
||||
{
|
||||
Total = distinctByKeyItemsWithReferencedRelations.Total,
|
||||
Items = _umbracoMapper.MapEnumerable<RelationItemModel, ReferenceByIdModel>(distinctByKeyItemsWithReferencedRelations.Items),
|
||||
Items = _umbracoMapper.MapEnumerable<Guid, ReferenceByIdModel>(distinctByKeyItemsWithReferencedRelations.Items),
|
||||
};
|
||||
|
||||
return await Task.FromResult(pagedViewModel);
|
||||
|
||||
@@ -22,7 +22,7 @@ public class ReferencedByDocumentController : DocumentControllerBase
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used by info tabs on content, media etc. and for the delete and unpublish of single items.
|
||||
|
||||
@@ -22,7 +22,7 @@ public class ReferencedDescendantsDocumentController : DocumentControllerBase
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used when deleting and unpublishing a single item to check if this item has any descending items that are in any
|
||||
|
||||
@@ -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<RelationItemModel> distinctByKeyItemsWithReferencedRelations = await _trackedReferencesSkipTakeService.GetPagedItemsWithRelationsAsync(ids, skip, take, true);
|
||||
PagedModel<Guid> distinctByKeyItemsWithReferencedRelations = await _trackedReferencesSkipTakeService.GetPagedKeysWithDependentReferencesAsync(ids, Constants.ObjectTypes.Media, skip, take);
|
||||
var pagedViewModel = new PagedViewModel<ReferenceByIdModel>
|
||||
{
|
||||
Total = distinctByKeyItemsWithReferencedRelations.Total,
|
||||
Items = _umbracoMapper.MapEnumerable<RelationItemModel, ReferenceByIdModel>(distinctByKeyItemsWithReferencedRelations.Items),
|
||||
Items = _umbracoMapper.MapEnumerable<Guid, ReferenceByIdModel>(distinctByKeyItemsWithReferencedRelations.Items),
|
||||
};
|
||||
|
||||
return await Task.FromResult(pagedViewModel);
|
||||
|
||||
@@ -13,6 +13,7 @@ public class TrackedReferenceViewModelsMapDefinition : IMapDefinition
|
||||
mapper.Define<RelationItemModel, MediaReferenceResponseModel>((source, context) => new MediaReferenceResponseModel(), Map);
|
||||
mapper.Define<RelationItemModel, DefaultReferenceResponseModel>((source, context) => new DefaultReferenceResponseModel(), Map);
|
||||
mapper.Define<RelationItemModel, ReferenceByIdModel>((source, context) => new ReferenceByIdModel(), Map);
|
||||
mapper.Define<Guid, ReferenceByIdModel>((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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,4 +131,14 @@ public interface ITrackedReferencesRepository
|
||||
long take,
|
||||
bool filterMustBeIsDependency,
|
||||
out long totalRecords);
|
||||
|
||||
Task<PagedModel<Guid>> GetPagedNodeKeysWithDependantReferencesAsync(
|
||||
ISet<Guid> keys,
|
||||
Guid nodeObjectTypeId,
|
||||
long skip,
|
||||
long take)
|
||||
{
|
||||
IEnumerable<RelationItemModel> pagedItems = GetPagedItemsWithRelations(keys, skip, take, true, out var total);
|
||||
return Task.FromResult(new PagedModel<Guid>(total, pagedItems.Select(i => i.NodeKey)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,4 +97,10 @@ public interface ITrackedReferencesService
|
||||
/// <returns>A paged result of <see cref="RelationItemModel" /> objects.</returns>
|
||||
Task<PagedModel<RelationItemModel>> GetPagedItemsWithRelationsAsync(ISet<Guid> keys, long skip, long take,
|
||||
bool filterMustBeIsDependency);
|
||||
|
||||
Task<PagedModel<Guid>> GetPagedKeysWithDependentReferencesAsync(ISet<Guid> keys, Guid nodeObjectTypeId, long skip, long take)
|
||||
{
|
||||
PagedModel<RelationItemModel> pagedItems = GetPagedItemsWithRelationsAsync(keys, skip, take, true).GetAwaiter().GetResult();
|
||||
return Task.FromResult(new PagedModel<Guid>(pagedItems.Total, pagedItems.Items.Select(i => i.NodeKey)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,4 +141,10 @@ public class TrackedReferencesService : ITrackedReferencesService
|
||||
|
||||
return await Task.FromResult(pagedModel);
|
||||
}
|
||||
|
||||
public async Task<PagedModel<Guid>> GetPagedKeysWithDependentReferencesAsync(ISet<Guid> keys, Guid objectTypeId, long skip, long take)
|
||||
{
|
||||
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
|
||||
return await _trackedReferencesRepository.GetPagedNodeKeysWithDependantReferencesAsync(keys, objectTypeId, skip, take);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -477,10 +477,49 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
|
||||
return _umbracoMapper.MapEnumerable<RelationItemDto, RelationItemModel>(pagedResult);
|
||||
}
|
||||
|
||||
public IEnumerable<RelationItemModel> GetPagedDescendantsInReferences(
|
||||
Guid parentKey,
|
||||
public async Task<PagedModel<Guid>> GetPagedNodeKeysWithDependantReferencesAsync(
|
||||
ISet<Guid> 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<ISqlContext>? sql = _scopeAccessor.AmbientScope.Database.SqlContext.Sql()
|
||||
.SelectDistinct<NodeDto>(node => node.UniqueId)
|
||||
.From<NodeDto>()
|
||||
.InnerJoin<RelationDto>()
|
||||
.On<NodeDto, RelationDto>((node, relation) =>
|
||||
node.NodeId == relation.ParentId || node.NodeId == relation.ParentId || node.NodeId == relation.ChildId)
|
||||
.InnerJoin<RelationTypeDto>()
|
||||
.On<RelationDto, RelationTypeDto>((relation, relationType) => relation.RelationType == relationType.Id && relationType.IsDependency)
|
||||
.Where<NodeDto, RelationDto, RelationTypeDto>(
|
||||
(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<Guid>(totalRecords, Enumerable.Empty<Guid>());
|
||||
}
|
||||
|
||||
// Ordering is required for paging
|
||||
sql = sql.OrderBy<NodeDto>(node => node.UniqueId);
|
||||
|
||||
IEnumerable<Guid> result = await _scopeAccessor.AmbientScope.Database.SkipTakeAsync<Guid>(skip, take, sql);
|
||||
|
||||
return new PagedModel<Guid>(totalRecords, result);
|
||||
}
|
||||
|
||||
public IEnumerable<RelationItemModel> GetPagedDescendantsInReferences(Guid parentKey, long skip, long take,
|
||||
bool filterMustBeIsDependency,
|
||||
out long totalRecords)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user