diff --git a/src/Umbraco.Core/Persistence/Repositories/ITrackedReferencesRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ITrackedReferencesRepository.cs
index a0a619b78d..b5f3ecf6fb 100644
--- a/src/Umbraco.Core/Persistence/Repositories/ITrackedReferencesRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/ITrackedReferencesRepository.cs
@@ -81,13 +81,17 @@ public interface ITrackedReferencesRepository
bool filterMustBeIsDependency,
out long totalRecords);
+ ///
+ /// Gets a paged collection of node keys that have dependant references.
+ ///
+ /// The keys to check for relations.
+ /// The node object Id.
+ /// The amount of items to skip.
+ /// The amount of items to take.
+ ///
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)));
- }
+ long take);
}
diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TrackedReferencesRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TrackedReferencesRepository.cs
index 8ddf8aae0b..c3ccb06e4f 100644
--- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TrackedReferencesRepository.cs
+++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TrackedReferencesRepository.cs
@@ -9,296 +9,24 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
{
+ ///
+ /// Implements to provide database access for tracked references."
+ ///
internal class TrackedReferencesRepository : ITrackedReferencesRepository
{
private readonly IScopeAccessor _scopeAccessor;
private readonly IUmbracoMapper _umbracoMapper;
+ ///
+ /// Initializes a new instance of the class.
+ ///
public TrackedReferencesRepository(IScopeAccessor scopeAccessor, IUmbracoMapper umbracoMapper)
{
_scopeAccessor = scopeAccessor;
_umbracoMapper = umbracoMapper;
}
- ///
- /// Gets a page of items used in any kind of relation from selected integer ids.
- ///
- public IEnumerable GetPagedItemsWithRelations(int[] ids, long pageIndex, int pageSize,
- bool filterMustBeIsDependency, out long totalRecords)
- {
- Sql innerUnionSql = GetInnerUnionSql();
-
- Sql? sql = _scopeAccessor.AmbientScope?.Database.SqlContext.Sql()
- .SelectDistinct(
- "[x].[id] as nodeId",
- "[n].[uniqueId] as nodeKey",
- "[n].[text] as nodeName",
- "[n].[nodeObjectType] as nodeObjectType",
- "[d].[published] as nodePublished",
- "[ctn].[uniqueId] as contentTypeKey",
- "[ct].[icon] as contentTypeIcon",
- "[ct].[alias] as contentTypeAlias",
- "[ctn].[text] as contentTypeName",
- "[x].[alias] as relationTypeAlias",
- "[x].[name] as relationTypeName",
- "[x].[isDependency] as relationTypeIsDependency",
- "[x].[dual] as relationTypeIsBidirectional")
- .From("n")
- .InnerJoinNested(innerUnionSql, "x")
- .On((n, x) => n.NodeId == x.Id, "n", "x")
- .LeftJoin("c")
- .On(
- (left, right) => left.NodeId == right.NodeId,
- aliasLeft: "n",
- aliasRight: "c")
- .LeftJoin("ct")
- .On(
- (left, right) => left.ContentTypeId == right.NodeId,
- aliasLeft: "c",
- aliasRight: "ct")
- .LeftJoin("ctn")
- .On(
- (left, right) => left.NodeId == right.NodeId,
- aliasLeft: "ct",
- aliasRight: "ctn")
- .LeftJoin("d")
- .On(
- (left, right) => left.NodeId == right.NodeId,
- aliasLeft: "n",
- aliasRight: "d");
-
- if (ids.Any())
- {
- sql = sql?.Where(x => ids.Contains(x.NodeId), "n");
- }
-
- if (filterMustBeIsDependency)
- {
- sql = sql?.Where(rt => rt.IsDependency, "x");
- }
-
- // Ordering is required for paging
- sql = sql?.OrderBy(x => x.Alias, "x");
-
- Page? pagedResult = _scopeAccessor.AmbientScope?.Database.Page(pageIndex + 1, pageSize, sql);
- totalRecords = Convert.ToInt32(pagedResult?.TotalItems);
-
- return pagedResult?.Items.Select(MapDtoToEntity) ?? Enumerable.Empty();
- }
-
- private Sql GetInnerUnionSql()
- {
- if (_scopeAccessor.AmbientScope is null)
- {
- throw new InvalidOperationException("No Ambient Scope available");
- }
-
- Sql innerUnionSqlChild = _scopeAccessor.AmbientScope.Database.SqlContext.Sql().Select(
- "[cn].uniqueId as [key]",
- "[cn].trashed as [trashed]",
- "[cn].nodeObjectType as [nodeObjectType]",
- "[pn].uniqueId as otherKey," +
- "[cr].childId as id",
- "[cr].parentId as otherId",
- "[rt].[alias]",
- "[rt].[name]",
- "[rt].[isDependency]",
- "[rt].[dual]")
- .From("cr")
- .InnerJoin("rt")
- .On((cr, rt) => rt.Dual == false && rt.Id == cr.RelationType, "cr", "rt")
- .InnerJoin("cn")
- .On((cr, cn) => cr.ChildId == cn.NodeId, "cr", "cn")
- .InnerJoin("pn")
- .On((cr, pn) => cr.ParentId == pn.NodeId, "cr", "pn");
-
- Sql innerUnionSqlDualParent = _scopeAccessor.AmbientScope.Database.SqlContext.Sql().Select(
- "[pn].uniqueId as [key]",
- "[pn].trashed as [trashed]",
- "[pn].nodeObjectType as [nodeObjectType]",
- "[cn].uniqueId as otherKey," +
- "[dpr].parentId as id",
- "[dpr].childId as otherId",
- "[dprt].[alias]",
- "[dprt].[name]",
- "[dprt].[isDependency]",
- "[dprt].[dual]")
- .From("dpr")
- .InnerJoin("dprt")
- .On(
- (dpr, dprt) => dprt.Dual == true && dprt.Id == dpr.RelationType, "dpr", "dprt")
- .InnerJoin("cn")
- .On((dpr, cn) => dpr.ChildId == cn.NodeId, "dpr", "cn")
- .InnerJoin("pn")
- .On((dpr, pn) => dpr.ParentId == pn.NodeId, "dpr", "pn");
-
- Sql innerUnionSql3 = _scopeAccessor.AmbientScope.Database.SqlContext.Sql().Select(
- "[cn].uniqueId as [key]",
- "[cn].trashed as [trashed]",
- "[cn].nodeObjectType as [nodeObjectType]",
- "[pn].uniqueId as otherKey," +
- "[dcr].childId as id",
- "[dcr].parentId as otherId",
- "[dcrt].[alias]",
- "[dcrt].[name]",
- "[dcrt].[isDependency]",
- "[dcrt].[dual]")
- .From("dcr")
- .InnerJoin("dcrt")
- .On(
- (dcr, dcrt) => dcrt.Dual == true && dcrt.Id == dcr.RelationType, "dcr", "dcrt")
- .InnerJoin("cn")
- .On((dcr, cn) => dcr.ChildId == cn.NodeId, "dcr", "cn")
- .InnerJoin("pn")
- .On((dcr, pn) => dcr.ParentId == pn.NodeId, "dcr", "pn");
-
- Sql innerUnionSql = innerUnionSqlChild.Union(innerUnionSqlDualParent).Union(innerUnionSql3);
-
- return innerUnionSql;
- }
-
- ///
- /// Gets a page of the descending items that have any references, given a parent id.
- ///
- public IEnumerable GetPagedDescendantsInReferences(
- int parentId,
- long pageIndex,
- int pageSize,
- bool filterMustBeIsDependency,
- out long totalRecords)
- {
- SqlSyntax.ISqlSyntaxProvider? syntax = _scopeAccessor.AmbientScope?.Database.SqlContext.SqlSyntax;
-
- // Gets the path of the parent with ",%" added
- Sql? subsubQuery = _scopeAccessor.AmbientScope?.Database.SqlContext.Sql()
- .Select(syntax?.GetConcat("[node].[path]", "',%'"))
- .From("node")
- .Where(x => x.NodeId == parentId, "node");
-
- // Gets the descendants of the parent node
- Sql? subQuery = _scopeAccessor.AmbientScope?.Database.SqlContext.Sql()
- .Select(x => x.NodeId)
- .From()
- .WhereLike(x => x.Path, subsubQuery);
-
- Sql innerUnionSql = GetInnerUnionSql();
-
- Sql? sql = _scopeAccessor.AmbientScope?.Database.SqlContext.Sql().SelectDistinct(
- "[x].[id] as nodeId",
- "[n].[uniqueId] as nodeKey",
- "[n].[text] as nodeName",
- "[n].[nodeObjectType] as nodeObjectType",
- "[d].[published] as nodePublished",
- "[ctn].[uniqueId] as contentTypeKey",
- "[ct].[icon] as contentTypeIcon",
- "[ct].[alias] as contentTypeAlias",
- "[ctn].[text] as contentTypeName",
- "[x].[alias] as relationTypeAlias",
- "[x].[name] as relationTypeName",
- "[x].[isDependency] as relationTypeIsDependency",
- "[x].[dual] as relationTypeIsBidirectional")
- .From("n")
- .InnerJoinNested(innerUnionSql, "x")
- .On((n, x) => n.NodeId == x.Id, "n", "x")
- .LeftJoin("c")
- .On(
- (left, right) => left.NodeId == right.NodeId,
- aliasLeft: "n",
- aliasRight: "c")
- .LeftJoin("ct")
- .On(
- (left, right) => left.ContentTypeId == right.NodeId,
- aliasLeft: "c",
- aliasRight: "ct")
- .LeftJoin("ctn")
- .On(
- (left, right) => left.NodeId == right.NodeId,
- aliasLeft: "ct",
- aliasRight: "ctn")
- .LeftJoin("d")
- .On(
- (left, right) => left.NodeId == right.NodeId,
- aliasLeft: "n",
- aliasRight: "d");
-
- sql = sql?.WhereIn((System.Linq.Expressions.Expression>)(x => x.NodeId), subQuery, "n");
-
- if (filterMustBeIsDependency)
- {
- sql = sql?.Where(rt => rt.IsDependency, "x");
- }
-
- // Ordering is required for paging
- sql = sql?.OrderBy(x => x.Alias, "x");
-
- Page? pagedResult = _scopeAccessor.AmbientScope?.Database.Page(pageIndex + 1, pageSize, sql);
- totalRecords = Convert.ToInt32(pagedResult?.TotalItems);
-
- return pagedResult?.Items.Select(MapDtoToEntity) ?? Enumerable.Empty();
- }
-
-
- ///
- /// Gets a page of items which are in relation with the current item.
- /// Basically, shows the items which depend on the current item.
- ///
- public IEnumerable GetPagedRelationsForItem(int id, long pageIndex, int pageSize,
- bool filterMustBeIsDependency, out long totalRecords)
- {
- Sql innerUnionSql = GetInnerUnionSql();
- Sql? sql = _scopeAccessor.AmbientScope?.Database.SqlContext.Sql().SelectDistinct(
- "[x].[otherId] as nodeId",
- "[n].[uniqueId] as nodeKey",
- "[n].[text] as nodeName",
- "[n].[nodeObjectType] as nodeObjectType",
- "[d].[published] as nodePublished",
- "[ctn].[uniqueId] as contentTypeKey",
- "[ct].[icon] as contentTypeIcon",
- "[ct].[alias] as contentTypeAlias",
- "[ctn].[text] as contentTypeName",
- "[x].[alias] as relationTypeAlias",
- "[x].[name] as relationTypeName",
- "[x].[isDependency] as relationTypeIsDependency",
- "[x].[dual] as relationTypeIsBidirectional")
- .From("n")
- .InnerJoinNested(innerUnionSql, "x")
- .On((n, x) => n.NodeId == x.OtherId, "n", "x")
- .LeftJoin("c")
- .On(
- (left, right) => left.NodeId == right.NodeId,
- aliasLeft: "n",
- aliasRight: "c")
- .LeftJoin("ct")
- .On(
- (left, right) => left.ContentTypeId == right.NodeId,
- aliasLeft: "c",
- aliasRight: "ct")
- .LeftJoin("ctn")
- .On(
- (left, right) => left.NodeId == right.NodeId,
- aliasLeft: "ct",
- aliasRight: "ctn")
- .LeftJoin("d")
- .On(
- (left, right) => left.NodeId == right.NodeId,
- aliasLeft: "n",
- aliasRight: "d")
- .Where(x => x.Id == id, "x");
-
- if (filterMustBeIsDependency)
- {
- sql = sql?.Where(rt => rt.IsDependency, "x");
- }
-
- // Ordering is required for paging
- sql = sql?.OrderBy(x => x.Alias, "x");
-
- Page? pagedResult = _scopeAccessor.AmbientScope?.Database.Page(pageIndex + 1, pageSize, sql);
- totalRecords = Convert.ToInt32(pagedResult?.TotalItems);
-
- return pagedResult?.Items.Select(MapDtoToEntity) ?? Enumerable.Empty();
- }
-
+ ///
public IEnumerable GetPagedRelationsForItem(
Guid key,
long skip,
@@ -312,6 +40,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
filterMustBeIsDependency,
out totalRecords);
+ ///
public IEnumerable GetPagedRelationsForRecycleBin(
Guid objectTypeKey,
long skip,
@@ -401,6 +130,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
return _umbracoMapper.MapEnumerable(pagedResult);
}
+ ///
public IEnumerable GetPagedItemsWithRelations(
ISet keys,
long skip,
@@ -466,6 +196,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
return _umbracoMapper.MapEnumerable(pagedResult);
}
+ ///
public async Task> GetPagedNodeKeysWithDependantReferencesAsync(
ISet keys,
Guid nodeObjectTypeId,
@@ -508,7 +239,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
return new PagedModel(totalRecords, result);
}
- public IEnumerable GetPagedDescendantsInReferences(Guid parentKey, long skip, long take,
+ ///
+ public IEnumerable GetPagedDescendantsInReferences(
+ Guid parentKey,
+ long skip,
+ long take,
bool filterMustBeIsDependency,
out long totalRecords)
{
@@ -596,89 +331,75 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
return _umbracoMapper.MapEnumerable(pagedResult);
}
- public IEnumerable GetPagedDescendantsInReferences(
- int parentId,
- long skip,
- long take,
- bool filterMustBeIsDependency,
- out long totalRecords)
+ private Sql GetInnerUnionSql()
{
- SqlSyntax.ISqlSyntaxProvider? syntax = _scopeAccessor.AmbientScope?.Database.SqlContext.SqlSyntax;
-
- // Gets the path of the parent with ",%" added
- Sql? subsubQuery = _scopeAccessor.AmbientScope?.Database.SqlContext.Sql()
- .Select(syntax?.GetConcat("[node].[path]", "',%'"))
- .From("node")
- .Where(x => x.NodeId == parentId, "node");
-
- // Gets the descendants of the parent node
- Sql? subQuery = _scopeAccessor.AmbientScope?.Database.SqlContext.Sql()
- .Select(x => x.NodeId)
- .From()
- .WhereLike(x => x.Path, subsubQuery);
-
- Sql innerUnionSql = GetInnerUnionSql();
- Sql? sql = _scopeAccessor.AmbientScope?.Database.SqlContext.Sql().SelectDistinct(
- "[x].[id] as nodeId",
- "[n].[uniqueId] as nodeKey",
- "[n].[text] as nodeName",
- "[n].[nodeObjectType] as nodeObjectType",
- "[ctn].[uniqueId] as contentTypeKey",
- "[ct].[icon] as contentTypeIcon",
- "[ct].[alias] as contentTypeAlias",
- "[ctn].[text] as contentTypeName",
- "[x].[alias] as relationTypeAlias",
- "[x].[name] as relationTypeName",
- "[x].[isDependency] as relationTypeIsDependency",
- "[x].[dual] as relationTypeIsBidirectional")
- .From("n")
- .InnerJoinNested(innerUnionSql, "x")
- .On((n, x) => n.NodeId == x.Id, "n", "x")
- .LeftJoin("c").On(
- (left, right) => left.NodeId == right.NodeId,
- aliasLeft: "n",
- aliasRight: "c")
- .LeftJoin("ct")
- .On(
- (left, right) => left.ContentTypeId == right.NodeId,
- aliasLeft: "c",
- aliasRight: "ct")
- .LeftJoin("ctn")
- .On(
- (left, right) => left.NodeId == right.NodeId,
- aliasLeft: "ct",
- aliasRight: "ctn");
- sql = sql?.WhereIn(
- (System.Linq.Expressions.Expression>)(x => x.NodeId),
- subQuery,
- "n");
-
- if (filterMustBeIsDependency)
+ if (_scopeAccessor.AmbientScope is null)
{
- sql = sql?.Where(rt => rt.IsDependency, "x");
+ throw new InvalidOperationException("No Ambient Scope available");
}
- // find the count before ordering
- totalRecords = _scopeAccessor.AmbientScope?.Database.Count(sql!) ?? 0;
+ Sql innerUnionSqlChild = _scopeAccessor.AmbientScope.Database.SqlContext.Sql().Select(
+ "[cn].uniqueId as [key]",
+ "[cn].trashed as [trashed]",
+ "[cn].nodeObjectType as [nodeObjectType]",
+ "[pn].uniqueId as otherKey," +
+ "[cr].childId as id",
+ "[cr].parentId as otherId",
+ "[rt].[alias]",
+ "[rt].[name]",
+ "[rt].[isDependency]",
+ "[rt].[dual]")
+ .From("cr")
+ .InnerJoin("rt")
+ .On((cr, rt) => rt.Dual == false && rt.Id == cr.RelationType, "cr", "rt")
+ .InnerJoin("cn")
+ .On((cr, cn) => cr.ChildId == cn.NodeId, "cr", "cn")
+ .InnerJoin("pn")
+ .On((cr, pn) => cr.ParentId == pn.NodeId, "cr", "pn");
- RelationItemDto[] pagedResult;
+ Sql innerUnionSqlDualParent = _scopeAccessor.AmbientScope.Database.SqlContext.Sql().Select(
+ "[pn].uniqueId as [key]",
+ "[pn].trashed as [trashed]",
+ "[pn].nodeObjectType as [nodeObjectType]",
+ "[cn].uniqueId as otherKey," +
+ "[dpr].parentId as id",
+ "[dpr].childId as otherId",
+ "[dprt].[alias]",
+ "[dprt].[name]",
+ "[dprt].[isDependency]",
+ "[dprt].[dual]")
+ .From("dpr")
+ .InnerJoin("dprt")
+ .On(
+ (dpr, dprt) => dprt.Dual == true && dprt.Id == dpr.RelationType, "dpr", "dprt")
+ .InnerJoin("cn")
+ .On((dpr, cn) => dpr.ChildId == cn.NodeId, "dpr", "cn")
+ .InnerJoin("pn")
+ .On((dpr, pn) => dpr.ParentId == pn.NodeId, "dpr", "pn");
- //Only to all this, if there is items
- if (totalRecords > 0)
- {
- // Ordering is required for paging
- sql = sql?.OrderBy(x => x.Alias, "x");
+ Sql innerUnionSql3 = _scopeAccessor.AmbientScope.Database.SqlContext.Sql().Select(
+ "[cn].uniqueId as [key]",
+ "[cn].trashed as [trashed]",
+ "[cn].nodeObjectType as [nodeObjectType]",
+ "[pn].uniqueId as otherKey," +
+ "[dcr].childId as id",
+ "[dcr].parentId as otherId",
+ "[dcrt].[alias]",
+ "[dcrt].[name]",
+ "[dcrt].[isDependency]",
+ "[dcrt].[dual]")
+ .From("dcr")
+ .InnerJoin("dcrt")
+ .On(
+ (dcr, dcrt) => dcrt.Dual == true && dcrt.Id == dcr.RelationType, "dcr", "dcrt")
+ .InnerJoin("cn")
+ .On((dcr, cn) => dcr.ChildId == cn.NodeId, "dcr", "cn")
+ .InnerJoin("pn")
+ .On((dcr, pn) => dcr.ParentId == pn.NodeId, "dcr", "pn");
- pagedResult =
- _scopeAccessor.AmbientScope?.Database.SkipTake(skip, take, sql).ToArray() ??
- Array.Empty();
- }
- else
- {
- pagedResult = Array.Empty();
- }
+ Sql innerUnionSql = innerUnionSqlChild.Union(innerUnionSqlDualParent).Union(innerUnionSql3);
- return _umbracoMapper.MapEnumerable(pagedResult);
+ return innerUnionSql;
}
private class UnionHelperDto
@@ -704,9 +425,8 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
[Column("dual")] public bool Dual { get; set; }
}
- private RelationItem MapDtoToEntity(RelationItemDto dto)
- {
- return new RelationItem()
+ private RelationItem MapDtoToEntity(RelationItemDto dto) =>
+ new()
{
NodeId = dto.ChildNodeId,
NodeKey = dto.ChildNodeKey,
@@ -721,6 +441,5 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
ContentTypeIcon = dto.ChildContentTypeIcon,
ContentTypeName = dto.ChildContentTypeName,
};
- }
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/rollback/entity-action/rollback.action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/rollback/entity-action/rollback.action.ts
index a486644add..3b9c94c806 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/rollback/entity-action/rollback.action.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/rollback/entity-action/rollback.action.ts
@@ -1,6 +1,6 @@
import { UMB_ROLLBACK_MODAL } from '../constants.js';
import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action';
-import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
+import { umbOpenModal } from '@umbraco-cms/backoffice/modal';
import { UMB_NOTIFICATION_CONTEXT } from '@umbraco-cms/backoffice/notification';
import { UmbLocalizationController } from '@umbraco-cms/backoffice/localization-api';
@@ -8,14 +8,7 @@ export class UmbRollbackDocumentEntityAction extends UmbEntityActionBase
#localize = new UmbLocalizationController(this);
override async execute() {
- const modalManagerContext = await this.getContext(UMB_MODAL_MANAGER_CONTEXT);
- if (!modalManagerContext) return;
-
- const modalContext = modalManagerContext.open(this, UMB_ROLLBACK_MODAL, {});
-
- const data = await modalContext.onSubmit().catch(() => undefined);
- if (!data) return;
-
+ await umbOpenModal(this, UMB_ROLLBACK_MODAL, {});
const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT);
if (!notificationContext) {
throw new Error('Notification context not found');