Use keys for tracked references (#13849)

* Use Keys for tracked references instead of int id's.

* Updated OpenApi.json

* Handle filterMustBeIsDependency consistently

---------

Co-authored-by: Nikolaj <nikolajlauridsen@protonmail.ch>
This commit is contained in:
Bjarke Berg
2023-02-21 15:20:34 +01:00
committed by GitHub
parent 2eebd0558c
commit 0619a7de41
13 changed files with 552 additions and 254 deletions

View File

@@ -27,16 +27,16 @@ public class ByIdTrackedReferenceController : TrackedReferenceControllerBase
/// Used by info tabs on content, media etc. and for the delete and unpublish of single items.
/// This is basically finding parents of relations.
/// </remarks>
[HttpGet("{id:int}")]
[HttpGet("{key:guid}")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedViewModel<RelationItemViewModel>), StatusCodes.Status200OK)]
public async Task<ActionResult<PagedViewModel<RelationItemViewModel>>> Get(
int id,
long skip,
long take,
bool? filterMustBeIsDependency)
Guid key,
long skip = 0,
long take = 20,
bool filterMustBeIsDependency = false)
{
PagedModel<RelationItemModel> relationItems = _trackedReferencesService.GetPagedRelationsForItem(id, skip, take, filterMustBeIsDependency ?? false);
PagedModel<RelationItemModel> relationItems = await _trackedReferencesService.GetPagedRelationsForItemAsync(key, skip, take, filterMustBeIsDependency);
var pagedViewModel = new PagedViewModel<RelationItemViewModel>
{

View File

@@ -28,12 +28,12 @@ public class DescendantsTrackedReferenceController : TrackedReferenceControllerB
/// kind of relation.
/// This is basically finding the descending items which are children in relations.
/// </remarks>
[HttpGet("descendants/{parentId:int}")]
[HttpGet("descendants/{parentKey:guid}")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedViewModel<RelationItemViewModel>), StatusCodes.Status200OK)]
public async Task<ActionResult<PagedViewModel<RelationItemViewModel>>> Descendants(int parentId, long skip, long take, bool? filterMustBeIsDependency)
public async Task<ActionResult<PagedViewModel<RelationItemViewModel>>> Descendants(Guid parentKey, long skip, long take, bool filterMustBeIsDependency = true)
{
PagedModel<RelationItemModel> relationItems = _trackedReferencesSkipTakeService.GetPagedDescendantsInReferences(parentId, skip, take, filterMustBeIsDependency ?? true);
PagedModel<RelationItemModel> relationItems = await _trackedReferencesSkipTakeService.GetPagedDescendantsInReferencesAsync(parentKey, skip, take, filterMustBeIsDependency);
var pagedViewModel = new PagedViewModel<RelationItemViewModel>
{
Total = relationItems.Total,

View File

@@ -21,7 +21,7 @@ public class ItemsTrackedReferenceController : TrackedReferenceControllerBase
}
/// <summary>
/// Gets a page list of the items used in any kind of relation from selected integer ids.
/// Gets a page 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).
@@ -30,9 +30,9 @@ public class ItemsTrackedReferenceController : TrackedReferenceControllerBase
[HttpGet("item")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedViewModel<RelationItemViewModel>), StatusCodes.Status200OK)]
public async Task<ActionResult<PagedViewModel<RelationItemViewModel>>> GetPagedReferencedItems([FromQuery]int[] ids, long skip, long take, bool? filterMustBeIsDependency)
public async Task<ActionResult<PagedViewModel<RelationItemViewModel>>> GetPagedReferencedItems([FromQuery(Name="key")]SortedSet<Guid> keys, long skip = 0, long take = 20, bool filterMustBeIsDependency = true)
{
PagedModel<RelationItemModel> relationItems = _trackedReferencesSkipTakeService.GetPagedItemsWithRelations(ids, skip, take, filterMustBeIsDependency ?? true);
PagedModel<RelationItemModel> relationItems = await _trackedReferencesSkipTakeService.GetPagedItemsWithRelationsAsync(keys, skip, take, filterMustBeIsDependency);
var pagedViewModel = new PagedViewModel<RelationItemViewModel>
{
Total = relationItems.Total,

View File

@@ -23,6 +23,7 @@ public class TrackedReferenceViewModelsMapDefinition : IMapDefinition
target.RelationTypeIsBidirectional = source.RelationTypeIsBidirectional;
target.RelationTypeIsDependency = source.RelationTypeIsDependency;
target.RelationTypeName = source.RelationTypeName;
target.NodePublished = source.NodePublished;
}
}

View File

@@ -702,6 +702,9 @@
}
}
},
"404": {
"description": "Not Found"
},
"400": {
"description": "Bad Request",
"content": {
@@ -712,9 +715,6 @@
}
}
},
"404": {
"description": "Not Found"
},
"409": {
"description": "Conflict",
"content": {
@@ -998,9 +998,7 @@
],
"operationId": "PostDictionaryUpload",
"requestBody": {
"content": {
}
"content": { }
},
"responses": {
"200": {
@@ -1496,6 +1494,9 @@
}
],
"responses": {
"401": {
"description": "Unauthorized"
},
"200": {
"description": "Success",
"content": {
@@ -1505,9 +1506,6 @@
}
}
}
},
"401": {
"description": "Unauthorized"
}
}
}
@@ -1539,6 +1537,9 @@
}
],
"responses": {
"401": {
"description": "Unauthorized"
},
"200": {
"description": "Success",
"content": {
@@ -1548,9 +1549,6 @@
}
}
}
},
"401": {
"description": "Unauthorized"
}
}
}
@@ -1785,6 +1783,9 @@
}
],
"responses": {
"404": {
"description": "Not Found"
},
"200": {
"description": "Success",
"content": {
@@ -1798,9 +1799,6 @@
}
}
}
},
"404": {
"description": "Not Found"
}
}
}
@@ -1822,6 +1820,9 @@
}
],
"responses": {
"404": {
"description": "Not Found"
},
"200": {
"description": "Success",
"content": {
@@ -1835,9 +1836,6 @@
}
}
}
},
"404": {
"description": "Not Found"
}
}
}
@@ -1862,6 +1860,16 @@
}
},
"responses": {
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetailsModel"
}
}
}
},
"200": {
"description": "Success",
"content": {
@@ -1875,16 +1883,6 @@
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetailsModel"
}
}
}
}
}
}
@@ -1936,16 +1934,6 @@
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PagedHelpPageModel"
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
@@ -1955,6 +1943,16 @@
}
}
}
},
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PagedHelpPageModel"
}
}
}
}
}
}
@@ -2014,6 +2012,16 @@
}
],
"responses": {
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetailsModel"
}
}
}
},
"200": {
"description": "Success",
"content": {
@@ -2027,16 +2035,6 @@
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetailsModel"
}
}
}
}
}
}
@@ -2058,16 +2056,6 @@
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/OkResultModel"
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
@@ -2077,6 +2065,16 @@
}
}
}
},
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/OkResultModel"
}
}
}
}
}
}
@@ -2088,20 +2086,6 @@
],
"operationId": "GetInstallSettings",
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"oneOf": [
{
"$ref": "#/components/schemas/InstallSettingsModel"
}
]
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
@@ -2121,6 +2105,20 @@
}
}
}
},
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"oneOf": [
{
"$ref": "#/components/schemas/InstallSettingsModel"
}
]
}
}
}
}
}
}
@@ -2145,9 +2143,6 @@
}
},
"responses": {
"200": {
"description": "Success"
},
"400": {
"description": "Bad Request",
"content": {
@@ -2167,6 +2162,9 @@
}
}
}
},
"200": {
"description": "Success"
}
}
}
@@ -2191,9 +2189,6 @@
}
},
"responses": {
"200": {
"description": "Success"
},
"400": {
"description": "Bad Request",
"content": {
@@ -2203,6 +2198,9 @@
}
}
}
},
"200": {
"description": "Success"
}
}
}
@@ -2265,6 +2263,19 @@
}
},
"responses": {
"404": {
"description": "Not Found"
},
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetailsModel"
}
}
}
},
"201": {
"description": "Created",
"headers": {
@@ -2277,19 +2288,6 @@
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetailsModel"
}
}
}
},
"404": {
"description": "Not Found"
}
}
}
@@ -2311,6 +2309,9 @@
}
],
"responses": {
"404": {
"description": "Not Found"
},
"200": {
"description": "Success",
"content": {
@@ -2324,9 +2325,6 @@
}
}
}
},
"404": {
"description": "Not Found"
}
}
},
@@ -2346,9 +2344,6 @@
}
],
"responses": {
"200": {
"description": "Success"
},
"400": {
"description": "Bad Request",
"content": {
@@ -2368,6 +2363,9 @@
}
}
}
},
"200": {
"description": "Success"
}
}
},
@@ -2400,8 +2398,8 @@
}
},
"responses": {
"200": {
"description": "Success"
"404": {
"description": "Not Found"
},
"400": {
"description": "Bad Request",
@@ -2413,8 +2411,8 @@
}
}
},
"404": {
"description": "Not Found"
"200": {
"description": "Success"
}
}
}
@@ -2484,9 +2482,6 @@
}
],
"responses": {
"200": {
"description": "Success"
},
"400": {
"description": "Bad Request",
"content": {
@@ -2496,6 +2491,9 @@
}
}
}
},
"200": {
"description": "Success"
}
}
}
@@ -2623,16 +2621,6 @@
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PagedLogTemplateModel"
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
@@ -2642,6 +2630,16 @@
}
}
}
},
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PagedLogTemplateModel"
}
}
}
}
}
}
@@ -2704,6 +2702,16 @@
}
},
"responses": {
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetailsModel"
}
}
}
},
"201": {
"description": "Created",
"headers": {
@@ -2716,16 +2724,6 @@
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetailsModel"
}
}
}
}
}
}
@@ -2747,6 +2745,9 @@
}
],
"responses": {
"404": {
"description": "Not Found"
},
"200": {
"description": "Success",
"content": {
@@ -2760,9 +2761,6 @@
}
}
}
},
"404": {
"description": "Not Found"
}
}
},
@@ -2782,11 +2780,11 @@
}
],
"responses": {
"200": {
"description": "Success"
},
"404": {
"description": "Not Found"
},
"200": {
"description": "Success"
}
}
}
@@ -2816,9 +2814,6 @@
}
],
"responses": {
"200": {
"description": "Success"
},
"400": {
"description": "Bad Request",
"content": {
@@ -2828,6 +2823,9 @@
}
}
}
},
"200": {
"description": "Success"
}
}
}
@@ -3014,6 +3012,9 @@
}
],
"responses": {
"401": {
"description": "Unauthorized"
},
"200": {
"description": "Success",
"content": {
@@ -3023,9 +3024,6 @@
}
}
}
},
"401": {
"description": "Unauthorized"
}
}
}
@@ -3057,6 +3055,9 @@
}
],
"responses": {
"401": {
"description": "Unauthorized"
},
"200": {
"description": "Success",
"content": {
@@ -3066,9 +3067,6 @@
}
}
}
},
"401": {
"description": "Unauthorized"
}
}
}
@@ -3730,16 +3728,6 @@
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PagedRedirectUrlModel"
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
@@ -3749,6 +3737,16 @@
}
}
}
},
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PagedRedirectUrlModel"
}
}
}
}
}
}
@@ -4300,6 +4298,16 @@
],
"operationId": "GetServerStatus",
"responses": {
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetailsModel"
}
}
}
},
"200": {
"description": "Success",
"content": {
@@ -4313,16 +4321,6 @@
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetailsModel"
}
}
}
}
}
}
@@ -4334,6 +4332,16 @@
],
"operationId": "GetServerVersion",
"responses": {
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetailsModel"
}
}
}
},
"200": {
"description": "Success",
"content": {
@@ -4347,16 +4355,6 @@
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetailsModel"
}
}
}
}
}
}
@@ -4693,9 +4691,6 @@
}
},
"responses": {
"200": {
"description": "Success"
},
"400": {
"description": "Bad Request",
"content": {
@@ -4705,6 +4700,9 @@
}
}
}
},
"200": {
"description": "Success"
}
}
}
@@ -5110,20 +5108,20 @@
}
}
},
"/umbraco/management/api/v1/tracked-reference/{id}": {
"/umbraco/management/api/v1/tracked-reference/{key}": {
"get": {
"tags": [
"Tracked Reference"
],
"operationId": "GetTrackedReferenceById",
"operationId": "GetTrackedReferenceByKey",
"parameters": [
{
"name": "id",
"name": "key",
"in": "path",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
"type": "string",
"format": "uuid"
}
},
{
@@ -5131,7 +5129,8 @@
"in": "query",
"schema": {
"type": "integer",
"format": "int64"
"format": "int64",
"default": 0
}
},
{
@@ -5139,14 +5138,16 @@
"in": "query",
"schema": {
"type": "integer",
"format": "int64"
"format": "int64",
"default": 20
}
},
{
"name": "filterMustBeIsDependency",
"in": "query",
"schema": {
"type": "boolean"
"type": "boolean",
"default": false
}
}
],
@@ -5164,20 +5165,20 @@
}
}
},
"/umbraco/management/api/v1/tracked-reference/descendants/{parentId}": {
"/umbraco/management/api/v1/tracked-reference/descendants/{parentKey}": {
"get": {
"tags": [
"Tracked Reference"
],
"operationId": "GetTrackedReferenceDescendantsByParentId",
"operationId": "GetTrackedReferenceDescendantsByParentKey",
"parameters": [
{
"name": "parentId",
"name": "parentKey",
"in": "path",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
"type": "string",
"format": "uuid"
}
},
{
@@ -5226,13 +5227,14 @@
"operationId": "GetTrackedReferenceItem",
"parameters": [
{
"name": "ids",
"name": "key",
"in": "query",
"schema": {
"uniqueItems": true,
"type": "array",
"items": {
"type": "integer",
"format": "int32"
"type": "string",
"format": "uuid"
}
}
},
@@ -5241,7 +5243,8 @@
"in": "query",
"schema": {
"type": "integer",
"format": "int64"
"format": "int64",
"default": 0
}
},
{
@@ -5249,14 +5252,16 @@
"in": "query",
"schema": {
"type": "integer",
"format": "int64"
"format": "int64",
"default": 20
}
},
{
"name": "filterMustBeIsDependency",
"in": "query",
"schema": {
"type": "boolean"
"type": "boolean",
"default": true
}
}
],
@@ -5361,6 +5366,16 @@
}
},
"responses": {
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetailsModel"
}
}
}
},
"201": {
"description": "Created",
"headers": {
@@ -5373,16 +5388,6 @@
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetailsModel"
}
}
}
}
}
},
@@ -6765,9 +6770,7 @@
},
"providerProperties": {
"type": "object",
"additionalProperties": {
},
"additionalProperties": { },
"nullable": true
}
},
@@ -7696,9 +7699,7 @@
"nullable": true
}
},
"additionalProperties": {
}
"additionalProperties": { }
},
"ProfilingStatusModel": {
"type": "object",
@@ -7919,6 +7920,10 @@
"type": "string",
"nullable": true
},
"nodePublished": {
"type": "boolean",
"nullable": true
},
"contentTypeIcon": {
"type": "string",
"nullable": true
@@ -8561,9 +8566,7 @@
"authorizationCode": {
"authorizationUrl": "/umbraco/management/api/v1.0/security/back-office/authorize",
"tokenUrl": "/umbraco/management/api/v1.0/security/back-office/token",
"scopes": {
}
"scopes": { }
}
}
}
@@ -8571,9 +8574,7 @@
},
"security": [
{
"OAuth": [
]
"OAuth": [ ]
}
]
}

View File

@@ -8,6 +8,8 @@ public class RelationItemViewModel
public string? NodeType { get; set; }
public bool? NodePublished { get; set; }
public string? ContentTypeIcon { get; set; }
public string? ContentTypeAlias { get; set; }
@@ -19,4 +21,5 @@ public class RelationItemViewModel
public bool RelationTypeIsBidirectional { get; set; }
public bool RelationTypeIsDependency { get; set; }
}

View File

@@ -8,6 +8,8 @@ public class RelationItemModel
public string? NodeType { get; set; }
public bool? NodePublished { get; set; }
public string? ContentTypeIcon { get; set; }
public string? ContentTypeAlias { get; set; }

View File

@@ -17,6 +17,7 @@ public interface ITrackedReferencesRepository
/// </param>
/// <param name="totalRecords">The total count of the items with reference to the current item.</param>
/// <returns>An enumerable list of <see cref="RelationItem" /> objects.</returns>
[Obsolete("Use overload that takes key instead of id. This will be removed in Umbraco 15.")]
IEnumerable<RelationItem> GetPagedRelationsForItem(int id, long pageIndex, int pageSize, bool filterMustBeIsDependency, out long totalRecords);
/// <summary>
@@ -31,6 +32,7 @@ public interface ITrackedReferencesRepository
/// </param>
/// <param name="totalRecords">The total count of the items in any kind of relation.</param>
/// <returns>An enumerable list of <see cref="RelationItem" /> objects.</returns>
[Obsolete("Use overload that takes key instead of id. This will be removed in Umbraco 15.")]
IEnumerable<RelationItem> GetPagedItemsWithRelations(int[] ids, long pageIndex, int pageSize, bool filterMustBeIsDependency, out long totalRecords);
/// <summary>
@@ -45,6 +47,7 @@ public interface ITrackedReferencesRepository
/// </param>
/// <param name="totalRecords">The total count of descending items.</param>
/// <returns>An enumerable list of <see cref="RelationItem" /> objects.</returns>
[Obsolete("Use overload that takes key instead of id. This will be removed in Umbraco 15.")]
IEnumerable<RelationItem> GetPagedDescendantsInReferences(int parentId, long pageIndex, int pageSize, bool filterMustBeIsDependency, out long totalRecords);
/// <summary>
@@ -60,6 +63,15 @@ public interface ITrackedReferencesRepository
/// </param>
/// <param name="totalRecords">The total count of the items with reference to the current item.</param>
/// <returns>An enumerable list of <see cref="RelationItem" /> objects.</returns>
IEnumerable<RelationItemModel> GetPagedRelationsForItem(
Guid key,
long skip,
long take,
bool filterMustBeIsDependency,
out long totalRecords) =>
throw new NotImplementedException();
[Obsolete("Use overload that takes key instead of id. This will be removed in Umbraco 15.")]
IEnumerable<RelationItemModel> GetPagedRelationsForItem(
int id,
long skip,
@@ -80,18 +92,25 @@ public interface ITrackedReferencesRepository
/// </param>
/// <param name="totalRecords">The total count of the items in any kind of relation.</param>
/// <returns>An enumerable list of <see cref="RelationItem" /> objects.</returns>
IEnumerable<RelationItemModel> GetPagedItemsWithRelations(
ISet<Guid> keys,
long skip,
long take,
bool filterMustBeIsDependency,
out long totalRecords);
[Obsolete("Use overload that takes key instead of id. This will be removed in Umbraco 15.")]
IEnumerable<RelationItemModel> GetPagedItemsWithRelations(
int[] ids,
long skip,
long take,
bool filterMustBeIsDependency,
out long totalRecords) =>
throw new NotImplementedException();
out long totalRecords);
/// <summary>
/// Gets a page of the descending items that have any references, given a parent id.
/// </summary>
/// <param name="parentId">The unique identifier of the parent to retrieve descendants for.</param>
/// <param name="parentKey">The unique identifier of the parent to retrieve descendants for.</param>
/// <param name="skip">The amount of items to skip.</param>
/// <param name="take">The amount of items to take.</param>
/// <param name="filterMustBeIsDependency">
@@ -100,11 +119,18 @@ public interface ITrackedReferencesRepository
/// </param>
/// <param name="totalRecords">The total count of descending items.</param>
/// <returns>An enumerable list of <see cref="RelationItem" /> objects.</returns>
IEnumerable<RelationItemModel> GetPagedDescendantsInReferences(
Guid parentKey,
long skip,
long take,
bool filterMustBeIsDependency,
out long totalRecords);
[Obsolete("Use overload that takes key instead of id. This will be removed in Umbraco 15.")]
IEnumerable<RelationItemModel> GetPagedDescendantsInReferences(
int parentId,
long skip,
long take,
bool filterMustBeIsDependency,
out long totalRecords) =>
throw new NotImplementedException();
out long totalRecords);
}

View File

@@ -17,6 +17,7 @@ public interface ITrackedReferencesService
/// dependencies (isDependency field is set to true).
/// </param>
/// <returns>A paged result of <see cref="RelationItem" /> objects.</returns>
[Obsolete("Use overload that takes key instead of id. This will be removed in Umbraco 15.")]
PagedResult<RelationItem> GetPagedRelationsForItem(int id, long pageIndex, int pageSize, bool filterMustBeIsDependency);
/// <summary>
@@ -30,6 +31,7 @@ public interface ITrackedReferencesService
/// dependencies (isDependency field is set to true).
/// </param>
/// <returns>A paged result of <see cref="RelationItem" /> objects.</returns>
[Obsolete("Use overload that takes key instead of id. This will be removed in Umbraco 15.")]
PagedResult<RelationItem> GetPagedDescendantsInReferences(int parentId, long pageIndex, int pageSize, bool filterMustBeIsDependency);
/// <summary>
@@ -43,9 +45,13 @@ public interface ITrackedReferencesService
/// dependencies (isDependency field is set to true).
/// </param>
/// <returns>A paged result of <see cref="RelationItem" /> objects.</returns>
[Obsolete("Use method that takes key (Guid) instead of id (int). This will be removed in Umbraco 15.")]
PagedResult<RelationItem> GetPagedItemsWithRelations(int[] ids, long pageIndex, int pageSize, bool filterMustBeIsDependency);
/// <summary>
[Obsolete("Use method that takes key (Guid) instead of id (int). This will be removed in Umbraco 15.")]
PagedModel<RelationItemModel> GetPagedRelationsForItem(int id, long skip, long take, bool filterMustBeIsDependency);
/// <summary>
/// Gets a paged result of items which are in relation with the current item.
/// Basically, shows the items which depend on the current item.
/// </summary>
@@ -58,26 +64,32 @@ public interface ITrackedReferencesService
/// </param>
/// <param name="totalItems">The total amount of items.</param>
/// <returns>A paged result of <see cref="RelationItemModel" /> objects.</returns>
PagedModel<RelationItemModel> GetPagedRelationsForItem(int id, long skip, long take, bool filterMustBeIsDependency) => throw new NotImplementedException();
Task<PagedModel<RelationItemModel>> GetPagedRelationsForItemAsync(Guid key, long skip, long take, bool filterMustBeIsDependency);
[Obsolete("Use method that takes key (Guid) instead of id (int). This will be removed in Umbraco 15.")]
PagedModel<RelationItemModel> GetPagedDescendantsInReferences(int parentId, long skip, long take, bool filterMustBeIsDependency);
/// <summary>
/// Gets a paged result of the descending items that have any references, given a parent id.
/// </summary>
/// <param name="parentId">The unique identifier of the parent to retrieve descendants for.</param>
/// <param name="parentKey">The unique identifier of the parent to retrieve descendants for.</param>
/// <param name="skip">The amount of items to skip</param>
/// <param name="take">The amount of items to take.</param>
/// <param name="filterMustBeIsDependency">
/// A boolean indicating whether to filter only the RelationTypes which are
/// dependencies (isDependency field is set to true).
/// </param>
/// <param name="totalItems">The total amount of items.</param>
/// <returns>A paged result of <see cref="RelationItemModel" /> objects.</returns>
PagedModel<RelationItemModel> GetPagedDescendantsInReferences(int parentId, long skip, long take, bool filterMustBeIsDependency) => throw new NotImplementedException();
Task<PagedModel<RelationItemModel>> GetPagedDescendantsInReferencesAsync(Guid parentKey, long skip, long take, bool filterMustBeIsDependency);
[Obsolete("Use method that takes keys (Guid) instead of ids (int). This will be removed in Umbraco 15.")]
PagedModel<RelationItemModel> GetPagedItemsWithRelations(int[] ids, long skip, long take,
bool filterMustBeIsDependency);
/// <summary>
/// Gets a paged result of items used in any kind of relation from selected integer ids.
/// </summary>
/// <param name="ids">The identifiers of the entities to check for relations.</param>
/// <param name="keys">The identifiers of the entities to check for relations.</param>
/// <param name="skip">The amount of items to skip</param>
/// <param name="take">The amount of items to take.</param>
/// <param name="filterMustBeIsDependency">
@@ -86,5 +98,6 @@ public interface ITrackedReferencesService
/// </param>
/// <param name="totalItems">The total amount of items.</param>
/// <returns>A paged result of <see cref="RelationItemModel" /> objects.</returns>
PagedModel<RelationItemModel> GetPagedItemsWithRelations(int[] ids, long skip, long take, bool filterMustBeIsDependency) => throw new NotImplementedException();
Task<PagedModel<RelationItemModel>> GetPagedItemsWithRelationsAsync(ISet<Guid> keys, long skip, long take,
bool filterMustBeIsDependency);
}

View File

@@ -1,3 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Persistence.Repositories;
using Umbraco.Cms.Core.Scoping;
@@ -8,28 +10,33 @@ namespace Umbraco.Cms.Core.Services;
public class TrackedReferencesService : ITrackedReferencesService
{
private readonly ICoreScopeProvider _scopeProvider;
private readonly IEntityService _entityService;
private readonly ITrackedReferencesRepository _trackedReferencesRepository;
[Obsolete("Please use ctor that does not take an IEntityService, scheduled for removal in V12")]
public TrackedReferencesService(
ITrackedReferencesRepository trackedReferencesRepository,
ICoreScopeProvider scopeProvider,
IEntityService entityService) : this(trackedReferencesRepository, scopeProvider)
{
}
public TrackedReferencesService(
ITrackedReferencesRepository trackedReferencesRepository,
ICoreScopeProvider scopeProvider)
IEntityService entityService)
{
_trackedReferencesRepository = trackedReferencesRepository;
_scopeProvider = scopeProvider;
_entityService = entityService;
}
[Obsolete("Please use ctor that does not take an IEntityService, scheduled for removal in V15")]
public TrackedReferencesService(
ITrackedReferencesRepository trackedReferencesRepository,
ICoreScopeProvider scopeProvider): this(trackedReferencesRepository, scopeProvider, StaticServiceProvider.Instance.GetRequiredService<IEntityService>())
{
}
/// <summary>
/// Gets a paged result of items which are in relation with the current item.
/// Basically, shows the items which depend on the current item.
/// </summary>
[Obsolete("Use overload that takes key instead of id. This will be removed in Umbraco 15.")]
public PagedResult<RelationItem> GetPagedRelationsForItem(int id, long pageIndex, int pageSize, bool filterMustBeIsDependency)
{
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
@@ -41,6 +48,7 @@ public class TrackedReferencesService : ITrackedReferencesService
/// <summary>
/// Gets a paged result of items used in any kind of relation from selected integer ids.
/// </summary>
[Obsolete("Use overload that takes key instead of id. This will be removed in Umbraco 15.")]
public PagedResult<RelationItem> GetPagedItemsWithRelations(int[] ids, long pageIndex, int pageSize, bool filterMustBeIsDependency)
{
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
@@ -52,6 +60,7 @@ public class TrackedReferencesService : ITrackedReferencesService
/// <summary>
/// Gets a paged result of the descending items that have any references, given a parent id.
/// </summary>
[Obsolete("Use overload that takes key instead of id. This will be removed in Umbraco 15.")]
public PagedResult<RelationItem> GetPagedDescendantsInReferences(int parentId, long pageIndex, int pageSize, bool filterMustBeIsDependency)
{
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
@@ -65,6 +74,7 @@ public class TrackedReferencesService : ITrackedReferencesService
return new PagedResult<RelationItem>(totalItems, pageIndex + 1, pageSize) { Items = items };
}
[Obsolete("Use overload that takes key instead of id. This will be removed in Umbraco 15.")]
public PagedModel<RelationItemModel> GetPagedRelationsForItem(int id, long skip, long take, bool filterMustBeIsDependency)
{
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
@@ -74,6 +84,16 @@ public class TrackedReferencesService : ITrackedReferencesService
return pagedModel;
}
public async Task<PagedModel<RelationItemModel>> GetPagedRelationsForItemAsync(Guid key, long skip, long take, bool filterMustBeIsDependency)
{
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
IEnumerable<RelationItemModel> items = _trackedReferencesRepository.GetPagedRelationsForItem(key, skip, take, filterMustBeIsDependency, out var totalItems);
var pagedModel = new PagedModel<RelationItemModel>(totalItems, items);
return await Task.FromResult(pagedModel);
}
[Obsolete("Use overload that takes key instead of id. This will be removed in Umbraco 15.")]
public PagedModel<RelationItemModel> GetPagedDescendantsInReferences(int parentId, long skip, long take, bool filterMustBeIsDependency)
{
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
@@ -89,6 +109,22 @@ public class TrackedReferencesService : ITrackedReferencesService
return pagedModel;
}
public async Task<PagedModel<RelationItemModel>> GetPagedDescendantsInReferencesAsync(Guid parentKey, long skip, long take, bool filterMustBeIsDependency)
{
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
IEnumerable<RelationItemModel> items = _trackedReferencesRepository.GetPagedDescendantsInReferences(
parentKey,
skip,
take,
filterMustBeIsDependency,
out var totalItems);
var pagedModel = new PagedModel<RelationItemModel>(totalItems, items);
return await Task.FromResult(pagedModel);
}
[Obsolete("Use overload that takes key instead of id. This will be removed in Umbraco 15.")]
public PagedModel<RelationItemModel> GetPagedItemsWithRelations(int[] ids, long skip, long take, bool filterMustBeIsDependency)
{
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
@@ -97,4 +133,13 @@ public class TrackedReferencesService : ITrackedReferencesService
return pagedModel;
}
public async Task<PagedModel<RelationItemModel>> GetPagedItemsWithRelationsAsync(ISet<Guid> keys, long skip, long take, bool filterMustBeIsDependency)
{
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
IEnumerable<RelationItemModel> items = _trackedReferencesRepository.GetPagedItemsWithRelations(keys, skip, take, filterMustBeIsDependency, out var totalItems);
var pagedModel = new PagedModel<RelationItemModel>(totalItems, items);
return await Task.FromResult(pagedModel);
}
}

View File

@@ -92,27 +92,39 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
}
var innerUnionSqlChild = _scopeAccessor.AmbientScope.Database.SqlContext.Sql().Select(
"[cr].childId as id", "[cr].parentId as otherId", "[rt].[alias]", "[rt].[name]",
"[cn].uniqueId as key", "[pn].uniqueId as otherKey, [cr].childId as id", "[cr].parentId as otherId", "[rt].[alias]", "[rt].[name]",
"[rt].[isDependency]", "[rt].[dual]")
.From<RelationDto>("cr")
.InnerJoin<RelationTypeDto>("rt")
.On<RelationDto, RelationTypeDto>((cr, rt) => rt.Dual == false && rt.Id == cr.RelationType, "cr", "rt");
.On<RelationDto, RelationTypeDto>((cr, rt) => rt.Dual == false && rt.Id == cr.RelationType, "cr", "rt")
.InnerJoin<NodeDto>("cn")
.On<RelationDto, NodeDto>((cr, cn) => cr.ChildId == cn.NodeId, "cr", "cn")
.InnerJoin<NodeDto>("pn")
.On<RelationDto, NodeDto>((cr, pn) => cr.ParentId == pn.NodeId, "cr", "pn");
var innerUnionSqlDualParent = _scopeAccessor.AmbientScope.Database.SqlContext.Sql().Select(
"[dpr].parentId as id", "[dpr].childId as otherId", "[dprt].[alias]", "[dprt].[name]",
"[pn].uniqueId as key", "[cn].uniqueId as otherKey, [dpr].parentId as id", "[dpr].childId as otherId", "[dprt].[alias]", "[dprt].[name]",
"[dprt].[isDependency]", "[dprt].[dual]")
.From<RelationDto>("dpr")
.InnerJoin<RelationTypeDto>("dprt")
.On<RelationDto, RelationTypeDto>(
(dpr, dprt) => dprt.Dual == true && dprt.Id == dpr.RelationType, "dpr", "dprt");
(dpr, dprt) => dprt.Dual == true && dprt.Id == dpr.RelationType, "dpr", "dprt")
.InnerJoin<NodeDto>("cn")
.On<RelationDto, NodeDto>((dpr, cn) => dpr.ChildId == cn.NodeId, "dpr", "cn")
.InnerJoin<NodeDto>("pn")
.On<RelationDto, NodeDto>((dpr, pn) => dpr.ParentId == pn.NodeId, "dpr", "pn");
var innerUnionSql3 = _scopeAccessor.AmbientScope.Database.SqlContext.Sql().Select(
"[dcr].childId as id", "[dcr].parentId as otherId", "[dcrt].[alias]", "[dcrt].[name]",
"[cn].uniqueId as key", "[pn].uniqueId as otherKey, [dcr].childId as id", "[dcr].parentId as otherId", "[dcrt].[alias]", "[dcrt].[name]",
"[dcrt].[isDependency]", "[dcrt].[dual]")
.From<RelationDto>("dcr")
.InnerJoin<RelationTypeDto>("dcrt")
.On<RelationDto, RelationTypeDto>(
(dcr, dcrt) => dcrt.Dual == true && dcrt.Id == dcr.RelationType, "dcr", "dcrt");
(dcr, dcrt) => dcrt.Dual == true && dcrt.Id == dcr.RelationType, "dcr", "dcrt")
.InnerJoin<NodeDto>("cn")
.On<RelationDto, NodeDto>((dcr, cn) => dcr.ChildId == cn.NodeId, "dcr", "cn")
.InnerJoin<NodeDto>("pn")
.On<RelationDto, NodeDto>((dcr, pn) => dcr.ParentId == pn.NodeId, "dcr", "pn");
var innerUnionSql = innerUnionSqlChild.Union(innerUnionSqlDualParent).Union(innerUnionSql3);
@@ -255,6 +267,69 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
return pagedResult?.Items.Select(MapDtoToEntity) ?? Enumerable.Empty<RelationItem>();
}
public IEnumerable<RelationItemModel> GetPagedRelationsForItem(
Guid key,
long skip,
long take,
bool filterMustBeIsDependency,
out long totalRecords)
{
Sql<ISqlContext> innerUnionSql = GetInnerUnionSql();
var 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",
"[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<NodeDto>("n")
.InnerJoinNested(innerUnionSql, "x")
.On<NodeDto, UnionHelperDto>((n, x) => n.NodeId == x.OtherId, "n", "x")
.LeftJoin<ContentDto>("c")
.On<NodeDto, ContentDto>(
(left, right) => left.NodeId == right.NodeId,
aliasLeft: "n",
aliasRight: "c")
.LeftJoin<ContentTypeDto>("ct")
.On<ContentDto, ContentTypeDto>(
(left, right) => left.ContentTypeId == right.NodeId,
aliasLeft: "c",
aliasRight: "ct")
.LeftJoin<NodeDto>("ctn")
.On<ContentTypeDto, NodeDto>(
(left, right) => left.NodeId == right.NodeId,
aliasLeft: "ct",
aliasRight: "ctn")
.LeftJoin<DocumentDto>("d")
.On<NodeDto, DocumentDto>(
(left, right) => left.NodeId == right.NodeId,
aliasLeft: "n",
aliasRight: "d")
.Where<UnionHelperDto>(x => x.Key == key, "x");
if (filterMustBeIsDependency)
{
sql = sql?.Where<RelationTypeDto>(rt => rt.IsDependency, "x");
}
// Ordering is required for paging
sql = sql?.OrderBy<RelationTypeDto>(x => x.Alias, "x");
RelationItemDto[] pagedResult =
_scopeAccessor.AmbientScope?.Database.SkipTake<RelationItemDto>(skip, take, sql).ToArray() ??
Array.Empty<RelationItemDto>();
totalRecords = _scopeAccessor.AmbientScope?.Database.Count(sql!) ?? 0;
return _umbracoMapper.MapEnumerable<RelationItemDto, RelationItemModel>(pagedResult);
}
[Obsolete("Use overload that takes key instead of id. This will be removed in Umbraco 15.")]
public IEnumerable<RelationItemModel> GetPagedRelationsForItem(
int id,
long skip,
@@ -299,11 +374,130 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
RelationItemDto[] pagedResult =
_scopeAccessor.AmbientScope?.Database.SkipTake<RelationItemDto>(skip, take, sql).ToArray() ??
Array.Empty<RelationItemDto>();
totalRecords = pagedResult.Length;
totalRecords = _scopeAccessor.AmbientScope?.Database.Count(sql!) ?? 0;
return _umbracoMapper.MapEnumerable<RelationItemDto, RelationItemModel>(pagedResult);
}
public IEnumerable<RelationItemModel> GetPagedItemsWithRelations(
ISet<Guid> keys,
long skip,
long take,
bool filterMustBeIsDependency,
out long totalRecords)
{
Sql<ISqlContext> innerUnionSql = GetInnerUnionSql();
Sql<ISqlContext>? sql = _scopeAccessor.AmbientScope?.Database.SqlContext.Sql().SelectDistinct(
"[x].[id] as nodeId",
"[n].[uniqueId] as nodeKey",
"[n].[text] as nodeName",
"[n].[nodeObjectType] as nodeObjectType",
"[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<NodeDto>("n")
.InnerJoinNested(innerUnionSql, "x")
.On<NodeDto, UnionHelperDto>((n, x) => n.NodeId == x.Id, "n", "x")
.LeftJoin<ContentDto>("c")
.On<NodeDto, ContentDto>((left, right) => left.NodeId == right.NodeId, aliasLeft: "n", aliasRight: "c")
.LeftJoin<ContentTypeDto>("ct")
.On<ContentDto, ContentTypeDto>((left, right) => left.ContentTypeId == right.NodeId, aliasLeft: "c",
aliasRight: "ct")
.LeftJoin<NodeDto>("ctn")
.On<ContentTypeDto, NodeDto>((left, right) => left.NodeId == right.NodeId, aliasLeft: "ct",
aliasRight: "ctn");
if (keys.Any())
{
sql = sql?.Where<NodeDto>(x => keys.Contains(x.UniqueId), "n");
}
if (filterMustBeIsDependency)
{
sql = sql?.Where<RelationTypeDto>(rt => rt.IsDependency, "x");
}
// Ordering is required for paging
sql = sql?.OrderBy<RelationTypeDto>(x => x.Alias, "x");
RelationItemDto[] pagedResult =
_scopeAccessor.AmbientScope?.Database.SkipTake<RelationItemDto>(skip, take, sql).ToArray() ??
Array.Empty<RelationItemDto>();
totalRecords = _scopeAccessor.AmbientScope?.Database.Count(sql!) ?? 0;
return _umbracoMapper.MapEnumerable<RelationItemDto, RelationItemModel>(pagedResult);
}
public IEnumerable<RelationItemModel> GetPagedDescendantsInReferences(Guid parentKey, long skip, long take, bool filterMustBeIsDependency,
out long totalRecords)
{
var syntax = _scopeAccessor.AmbientScope?.Database.SqlContext.SqlSyntax;
// Gets the path of the parent with ",%" added
var subsubQuery = _scopeAccessor.AmbientScope?.Database.SqlContext.Sql()
.Select(syntax?.GetConcat("[node].[path]", "',%'"))
.From<NodeDto>("node")
.Where<NodeDto>(x => x.UniqueId == parentKey, "node");
// Gets the descendants of the parent node
Sql<ISqlContext>? subQuery = _scopeAccessor.AmbientScope?.Database.SqlContext.Sql()
.Select<NodeDto>(x => x.NodeId)
.From<NodeDto>()
.WhereLike<NodeDto>(x => x.Path, subsubQuery);
Sql<ISqlContext> innerUnionSql = GetInnerUnionSql();
var 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",
"[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<NodeDto>("n")
.InnerJoinNested(innerUnionSql, "x")
.On<NodeDto, UnionHelperDto>((n, x) => n.NodeId == x.Id, "n", "x")
.LeftJoin<ContentDto>("c").On<NodeDto, ContentDto>((left, right) => left.NodeId == right.NodeId,
aliasLeft: "n", aliasRight: "c")
.LeftJoin<ContentTypeDto>("ct")
.On<ContentDto, ContentTypeDto>((left, right) => left.ContentTypeId == right.NodeId, aliasLeft: "c",
aliasRight: "ct")
.LeftJoin<NodeDto>("ctn")
.On<ContentTypeDto, NodeDto>((left, right) => left.NodeId == right.NodeId, aliasLeft: "ct",
aliasRight: "ctn")
.LeftJoin<DocumentDto>("d")
.On<NodeDto, DocumentDto>(
(left, right) => left.NodeId == right.NodeId,
aliasLeft: "n",
aliasRight: "d");
sql = sql?.WhereIn((System.Linq.Expressions.Expression<Func<NodeDto, object?>>)(x => x.NodeId), subQuery,
"n");
if (filterMustBeIsDependency)
{
sql = sql?.Where<RelationTypeDto>(rt => rt.IsDependency, "x");
}
// Ordering is required for paging
sql = sql?.OrderBy<RelationTypeDto>(x => x.Alias, "x");
List<RelationItemDto>? pagedResult = _scopeAccessor.AmbientScope?.Database.SkipTake<RelationItemDto>(skip, take, sql);
totalRecords = _scopeAccessor.AmbientScope?.Database.Count(sql!) ?? 0;
return _umbracoMapper.MapEnumerable<RelationItemDto, RelationItemModel>(pagedResult ??
new List<RelationItemDto>());
}
[Obsolete("Use overload that takes keys instead of ids. This will be removed in Umbraco 15.")]
public IEnumerable<RelationItemModel> GetPagedItemsWithRelations(
int[] ids,
long skip,
@@ -351,7 +545,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
RelationItemDto[] pagedResult =
_scopeAccessor.AmbientScope?.Database.SkipTake<RelationItemDto>(skip, take, sql).ToArray() ??
Array.Empty<RelationItemDto>();
totalRecords = pagedResult.Length;
totalRecords = _scopeAccessor.AmbientScope?.Database.Count(sql!) ?? 0;
return _umbracoMapper.MapEnumerable<RelationItemDto, RelationItemModel>(pagedResult);
}
@@ -414,7 +608,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
List<RelationItemDto>? pagedResult =
_scopeAccessor.AmbientScope?.Database.SkipTake<RelationItemDto>(skip, take, sql);
totalRecords = pagedResult?.Count ?? 0;
totalRecords = _scopeAccessor.AmbientScope?.Database.Count(sql!) ?? 0;
return _umbracoMapper.MapEnumerable<RelationItemDto, RelationItemModel>(pagedResult ??
new List<RelationItemDto>());
@@ -426,6 +620,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
[Column("otherId")] public int OtherId { get; set; }
[Column("key")] public Guid Key { get; set; }
[Column("otherKey")] public Guid OtherKey { get; set; }
[Column("alias")] public string? Alias { get; set; }
[Column("name")] public string? Name { get; set; }

View File

@@ -73,4 +73,11 @@ internal static class UmbracoDatabaseExtensions
/// <returns></returns>
public static bool IsDatabaseEmpty(this IUmbracoDatabase database)
=> database.SqlContext.SqlSyntax.GetTablesInSchema(database).Any() == false;
public static long Count(this IUmbracoDatabase database, Sql sql)
{
var query = new Sql().Select("COUNT(*)").From().Append("(").Append(sql).Append(")");
return database.ExecuteScalar<long>(query);
}
}

View File

@@ -22,5 +22,7 @@ public class RelationModelMapDefinition : IMapDefinition
target.ContentTypeAlias = source.ChildContentTypeAlias;
target.ContentTypeIcon = source.ChildContentTypeIcon;
target.ContentTypeName = source.ChildContentTypeName;
target.NodePublished = source.ChildNodePublished;
}
}