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 Microsoft.AspNetCore.Mvc;
|
||||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||||
using Umbraco.Cms.Api.Management.ViewModels;
|
using Umbraco.Cms.Api.Management.ViewModels;
|
||||||
|
using Umbraco.Cms.Core;
|
||||||
using Umbraco.Cms.Core.Mapping;
|
using Umbraco.Cms.Core.Mapping;
|
||||||
using Umbraco.Cms.Core.Models;
|
using Umbraco.Cms.Core.Models;
|
||||||
using Umbraco.Cms.Core.Services;
|
using Umbraco.Cms.Core.Services;
|
||||||
@@ -22,7 +23,7 @@ public class AreReferencedDocumentController : DocumentControllerBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Used when bulk deleting content/media and bulk unpublishing content (delete and unpublish on List view).
|
/// 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 skip = 0,
|
||||||
int take = 20)
|
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>
|
var pagedViewModel = new PagedViewModel<ReferenceByIdModel>
|
||||||
{
|
{
|
||||||
Total = distinctByKeyItemsWithReferencedRelations.Total,
|
Total = distinctByKeyItemsWithReferencedRelations.Total,
|
||||||
Items = _umbracoMapper.MapEnumerable<RelationItemModel, ReferenceByIdModel>(distinctByKeyItemsWithReferencedRelations.Items),
|
Items = _umbracoMapper.MapEnumerable<Guid, ReferenceByIdModel>(distinctByKeyItemsWithReferencedRelations.Items),
|
||||||
};
|
};
|
||||||
|
|
||||||
return await Task.FromResult(pagedViewModel);
|
return await Task.FromResult(pagedViewModel);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ public class ReferencedByDocumentController : DocumentControllerBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Used by info tabs on content, media etc. and for the delete and unpublish of single items.
|
/// 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>
|
/// <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>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Used when deleting and unpublishing a single item to check if this item has any descending items that are in any
|
/// 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 Microsoft.AspNetCore.Mvc;
|
||||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||||
using Umbraco.Cms.Api.Management.ViewModels;
|
using Umbraco.Cms.Api.Management.ViewModels;
|
||||||
|
using Umbraco.Cms.Core;
|
||||||
using Umbraco.Cms.Core.Mapping;
|
using Umbraco.Cms.Core.Mapping;
|
||||||
using Umbraco.Cms.Core.Models;
|
using Umbraco.Cms.Core.Models;
|
||||||
using Umbraco.Cms.Core.Services;
|
using Umbraco.Cms.Core.Services;
|
||||||
@@ -38,11 +39,11 @@ public class AreReferencedMediaController : MediaControllerBase
|
|||||||
int skip = 0,
|
int skip = 0,
|
||||||
int take = 20)
|
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>
|
var pagedViewModel = new PagedViewModel<ReferenceByIdModel>
|
||||||
{
|
{
|
||||||
Total = distinctByKeyItemsWithReferencedRelations.Total,
|
Total = distinctByKeyItemsWithReferencedRelations.Total,
|
||||||
Items = _umbracoMapper.MapEnumerable<RelationItemModel, ReferenceByIdModel>(distinctByKeyItemsWithReferencedRelations.Items),
|
Items = _umbracoMapper.MapEnumerable<Guid, ReferenceByIdModel>(distinctByKeyItemsWithReferencedRelations.Items),
|
||||||
};
|
};
|
||||||
|
|
||||||
return await Task.FromResult(pagedViewModel);
|
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, MediaReferenceResponseModel>((source, context) => new MediaReferenceResponseModel(), Map);
|
||||||
mapper.Define<RelationItemModel, DefaultReferenceResponseModel>((source, context) => new DefaultReferenceResponseModel(), Map);
|
mapper.Define<RelationItemModel, DefaultReferenceResponseModel>((source, context) => new DefaultReferenceResponseModel(), Map);
|
||||||
mapper.Define<RelationItemModel, ReferenceByIdModel>((source, context) => new ReferenceByIdModel(), Map);
|
mapper.Define<RelationItemModel, ReferenceByIdModel>((source, context) => new ReferenceByIdModel(), Map);
|
||||||
|
mapper.Define<Guid, ReferenceByIdModel>((source, context) => new ReferenceByIdModel(), Map);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Umbraco.Code.MapAll
|
// Umbraco.Code.MapAll
|
||||||
@@ -56,4 +57,10 @@ public class TrackedReferenceViewModelsMapDefinition : IMapDefinition
|
|||||||
{
|
{
|
||||||
target.Id = source.NodeKey;
|
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,
|
long take,
|
||||||
bool filterMustBeIsDependency,
|
bool filterMustBeIsDependency,
|
||||||
out long totalRecords);
|
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>
|
/// <returns>A paged result of <see cref="RelationItemModel" /> objects.</returns>
|
||||||
Task<PagedModel<RelationItemModel>> GetPagedItemsWithRelationsAsync(ISet<Guid> keys, long skip, long take,
|
Task<PagedModel<RelationItemModel>> GetPagedItemsWithRelationsAsync(ISet<Guid> keys, long skip, long take,
|
||||||
bool filterMustBeIsDependency);
|
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);
|
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);
|
return _umbracoMapper.MapEnumerable<RelationItemDto, RelationItemModel>(pagedResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<RelationItemModel> GetPagedDescendantsInReferences(
|
public async Task<PagedModel<Guid>> GetPagedNodeKeysWithDependantReferencesAsync(
|
||||||
Guid parentKey,
|
ISet<Guid> keys,
|
||||||
|
Guid nodeObjectTypeId,
|
||||||
long skip,
|
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,
|
bool filterMustBeIsDependency,
|
||||||
out long totalRecords)
|
out long totalRecords)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user