Skip to content

Commit 24ec0ee

Browse files
Migaroezbergmania
andauthored
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 d32b6ac. * Cleanup temporary renaming * Add default implementations * Fix merge issue --------- Co-authored-by: Bjarke Berg <[email protected]>
1 parent 0bf2fbc commit 24ec0ee

9 files changed

Lines changed: 80 additions & 10 deletions

File tree

src/Umbraco.Cms.Api.Management/Controllers/Document/References/AreReferencedDocumentController.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Microsoft.AspNetCore.Mvc;
44
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
55
using Umbraco.Cms.Api.Management.ViewModels;
6+
using Umbraco.Cms.Core;
67
using Umbraco.Cms.Core.Mapping;
78
using Umbraco.Cms.Core.Models;
89
using Umbraco.Cms.Core.Services;
@@ -22,7 +23,7 @@ public AreReferencedDocumentController(ITrackedReferencesService trackedReferenc
2223
}
2324

2425
/// <summary>
25-
/// Gets a page list of the items used in any kind of relation from selected keys.
26+
/// Gets a paged list of the items used in any kind of relation from selected keys.
2627
/// </summary>
2728
/// <remarks>
2829
/// Used when bulk deleting content/media and bulk unpublishing content (delete and unpublish on List view).
@@ -37,11 +38,11 @@ public async Task<ActionResult<PagedViewModel<ReferenceByIdModel>>> GetPagedRefe
3738
int skip = 0,
3839
int take = 20)
3940
{
40-
PagedModel<RelationItemModel> distinctByKeyItemsWithReferencedRelations = await _trackedReferencesSkipTakeService.GetPagedItemsWithRelationsAsync(ids, skip, take, true);
41+
PagedModel<Guid> distinctByKeyItemsWithReferencedRelations = await _trackedReferencesSkipTakeService.GetPagedKeysWithDependentReferencesAsync(ids, Constants.ObjectTypes.Document, skip, take);
4142
var pagedViewModel = new PagedViewModel<ReferenceByIdModel>
4243
{
4344
Total = distinctByKeyItemsWithReferencedRelations.Total,
44-
Items = _umbracoMapper.MapEnumerable<RelationItemModel, ReferenceByIdModel>(distinctByKeyItemsWithReferencedRelations.Items),
45+
Items = _umbracoMapper.MapEnumerable<Guid, ReferenceByIdModel>(distinctByKeyItemsWithReferencedRelations.Items),
4546
};
4647

4748
return await Task.FromResult(pagedViewModel);

src/Umbraco.Cms.Api.Management/Controllers/Document/References/ReferencedByDocumentController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public ReferencedByDocumentController(ITrackedReferencesService trackedReference
2222
}
2323

2424
/// <summary>
25-
/// Gets a page list of tracked references for the current item, so you can see where an item is being used.
25+
/// Gets a paged list of tracked references for the current item, so you can see where an item is being used.
2626
/// </summary>
2727
/// <remarks>
2828
/// Used by info tabs on content, media etc. and for the delete and unpublish of single items.

src/Umbraco.Cms.Api.Management/Controllers/Document/References/ReferencedDescendantsDocumentController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public ReferencedDescendantsDocumentController(ITrackedReferencesService tracked
2222
}
2323

2424
/// <summary>
25-
/// Gets a page list of the child nodes of the current item used in any kind of relation.
25+
/// Gets a paged list of the descendant nodes of the current item used in any kind of relation.
2626
/// </summary>
2727
/// <remarks>
2828
/// Used when deleting and unpublishing a single item to check if this item has any descending items that are in any

src/Umbraco.Cms.Api.Management/Controllers/Media/References/AreReferencedMediaController.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Microsoft.AspNetCore.Mvc;
44
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
55
using Umbraco.Cms.Api.Management.ViewModels;
6+
using Umbraco.Cms.Core;
67
using Umbraco.Cms.Core.Mapping;
78
using Umbraco.Cms.Core.Models;
89
using Umbraco.Cms.Core.Services;
@@ -38,11 +39,11 @@ public async Task<ActionResult<PagedViewModel<ReferenceByIdModel>>> GetPagedRefe
3839
int skip = 0,
3940
int take = 20)
4041
{
41-
PagedModel<RelationItemModel> distinctByKeyItemsWithReferencedRelations = await _trackedReferencesSkipTakeService.GetPagedItemsWithRelationsAsync(ids, skip, take, true);
42+
PagedModel<Guid> distinctByKeyItemsWithReferencedRelations = await _trackedReferencesSkipTakeService.GetPagedKeysWithDependentReferencesAsync(ids, Constants.ObjectTypes.Media, skip, take);
4243
var pagedViewModel = new PagedViewModel<ReferenceByIdModel>
4344
{
4445
Total = distinctByKeyItemsWithReferencedRelations.Total,
45-
Items = _umbracoMapper.MapEnumerable<RelationItemModel, ReferenceByIdModel>(distinctByKeyItemsWithReferencedRelations.Items),
46+
Items = _umbracoMapper.MapEnumerable<Guid, ReferenceByIdModel>(distinctByKeyItemsWithReferencedRelations.Items),
4647
};
4748

4849
return await Task.FromResult(pagedViewModel);

src/Umbraco.Cms.Api.Management/Mapping/TrackedReferences/TrackedReferenceViewModelsMapDefinition.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public void DefineMaps(IUmbracoMapper mapper)
1313
mapper.Define<RelationItemModel, MediaReferenceResponseModel>((source, context) => new MediaReferenceResponseModel(), Map);
1414
mapper.Define<RelationItemModel, DefaultReferenceResponseModel>((source, context) => new DefaultReferenceResponseModel(), Map);
1515
mapper.Define<RelationItemModel, ReferenceByIdModel>((source, context) => new ReferenceByIdModel(), Map);
16+
mapper.Define<Guid, ReferenceByIdModel>((source, context) => new ReferenceByIdModel(), Map);
1617
}
1718

1819
// Umbraco.Code.MapAll
@@ -56,4 +57,10 @@ private void Map(RelationItemModel source, ReferenceByIdModel target, MapperCont
5657
{
5758
target.Id = source.NodeKey;
5859
}
60+
61+
// Umbraco.Code.MapAll
62+
private void Map(Guid source, ReferenceByIdModel target, MapperContext context)
63+
{
64+
target.Id = source;
65+
}
5966
}

src/Umbraco.Core/Persistence/Repositories/ITrackedReferencesRepository.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,4 +131,14 @@ IEnumerable<RelationItemModel> GetPagedDescendantsInReferences(
131131
long take,
132132
bool filterMustBeIsDependency,
133133
out long totalRecords);
134+
135+
Task<PagedModel<Guid>> GetPagedNodeKeysWithDependantReferencesAsync(
136+
ISet<Guid> keys,
137+
Guid nodeObjectTypeId,
138+
long skip,
139+
long take)
140+
{
141+
IEnumerable<RelationItemModel> pagedItems = GetPagedItemsWithRelations(keys, skip, take, true, out var total);
142+
return Task.FromResult(new PagedModel<Guid>(total, pagedItems.Select(i => i.NodeKey)));
143+
}
134144
}

src/Umbraco.Core/Services/ITrackedReferencesService.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,10 @@ PagedModel<RelationItemModel> GetPagedItemsWithRelations(int[] ids, long skip, l
9797
/// <returns>A paged result of <see cref="RelationItemModel" /> objects.</returns>
9898
Task<PagedModel<RelationItemModel>> GetPagedItemsWithRelationsAsync(ISet<Guid> keys, long skip, long take,
9999
bool filterMustBeIsDependency);
100+
101+
Task<PagedModel<Guid>> GetPagedKeysWithDependentReferencesAsync(ISet<Guid> keys, Guid nodeObjectTypeId, long skip, long take)
102+
{
103+
PagedModel<RelationItemModel> pagedItems = GetPagedItemsWithRelationsAsync(keys, skip, take, true).GetAwaiter().GetResult();
104+
return Task.FromResult(new PagedModel<Guid>(pagedItems.Total, pagedItems.Items.Select(i => i.NodeKey)));
105+
}
100106
}

src/Umbraco.Core/Services/TrackedReferencesService.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,4 +141,10 @@ public async Task<PagedModel<RelationItemModel>> GetPagedItemsWithRelationsAsync
141141

142142
return await Task.FromResult(pagedModel);
143143
}
144+
145+
public async Task<PagedModel<Guid>> GetPagedKeysWithDependentReferencesAsync(ISet<Guid> keys, Guid objectTypeId, long skip, long take)
146+
{
147+
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
148+
return await _trackedReferencesRepository.GetPagedNodeKeysWithDependantReferencesAsync(keys, objectTypeId, skip, take);
149+
}
144150
}

src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TrackedReferencesRepository.cs

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -477,10 +477,49 @@ public IEnumerable<RelationItemModel> GetPagedItemsWithRelations(
477477
return _umbracoMapper.MapEnumerable<RelationItemDto, RelationItemModel>(pagedResult);
478478
}
479479

480-
public IEnumerable<RelationItemModel> GetPagedDescendantsInReferences(
481-
Guid parentKey,
480+
public async Task<PagedModel<Guid>> GetPagedNodeKeysWithDependantReferencesAsync(
481+
ISet<Guid> keys,
482+
Guid nodeObjectTypeId,
482483
long skip,
483-
long take,
484+
long take)
485+
{
486+
if (_scopeAccessor.AmbientScope is null)
487+
{
488+
throw new InvalidOperationException("Can not execute without a valid AmbientScope");
489+
}
490+
491+
Sql<ISqlContext>? sql = _scopeAccessor.AmbientScope.Database.SqlContext.Sql()
492+
.SelectDistinct<NodeDto>(node => node.UniqueId)
493+
.From<NodeDto>()
494+
.InnerJoin<RelationDto>()
495+
.On<NodeDto, RelationDto>((node, relation) =>
496+
node.NodeId == relation.ParentId || node.NodeId == relation.ParentId || node.NodeId == relation.ChildId)
497+
.InnerJoin<RelationTypeDto>()
498+
.On<RelationDto, RelationTypeDto>((relation, relationType) => relation.RelationType == relationType.Id && relationType.IsDependency)
499+
.Where<NodeDto, RelationDto, RelationTypeDto>(
500+
(node, relation, relationType)
501+
=> node.NodeObjectType == nodeObjectTypeId
502+
&& keys.Contains(node.UniqueId)
503+
&& (node.NodeId == relation.ChildId
504+
|| (relationType.Dual && relation.ParentId == node.NodeId)));
505+
506+
var totalRecords = _scopeAccessor.AmbientScope.Database.Count(sql);
507+
508+
// no need to process further if no records are found
509+
if (totalRecords < 1)
510+
{
511+
return new PagedModel<Guid>(totalRecords, Enumerable.Empty<Guid>());
512+
}
513+
514+
// Ordering is required for paging
515+
sql = sql.OrderBy<NodeDto>(node => node.UniqueId);
516+
517+
IEnumerable<Guid> result = await _scopeAccessor.AmbientScope.Database.SkipTakeAsync<Guid>(skip, take, sql);
518+
519+
return new PagedModel<Guid>(totalRecords, result);
520+
}
521+
522+
public IEnumerable<RelationItemModel> GetPagedDescendantsInReferences(Guid parentKey, long skip, long take,
484523
bool filterMustBeIsDependency,
485524
out long totalRecords)
486525
{

0 commit comments

Comments
 (0)