diff --git a/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs b/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs
index 211d36f65f..1c32dc3de6 100644
--- a/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs
+++ b/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs
@@ -3,12 +3,14 @@ using System.Globalization;
using System.Runtime.Serialization;
using System.Xml.Linq;
using Microsoft.Extensions.Logging;
+using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Editors;
using Umbraco.Cms.Core.Models.Validation;
using Umbraco.Cms.Core.PropertyEditors.Validators;
using Umbraco.Cms.Core.Serialization;
+using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
using Umbraco.Extensions;
@@ -20,6 +22,9 @@ namespace Umbraco.Cms.Core.PropertyEditors;
[DataContract]
public class DataValueEditor : IDataValueEditor
{
+ private const string ContentCacheKeyFormat = nameof(DataValueEditor) + "_Content_{0}";
+ private const string MediaCacheKeyFormat = nameof(DataValueEditor) + "_Media_{0}";
+
private readonly IJsonSerializer? _jsonSerializer;
private readonly IShortStringHelper _shortStringHelper;
@@ -415,4 +420,155 @@ public class DataValueEditor : IDataValueEditor
return value.TryConvertTo(valueType);
}
+
+ ///
+ /// Retrieves a instance by its unique identifier, using the provided request cache to avoid redundant
+ /// lookups within the same request.
+ ///
+ ///
+ /// This method caches content lookups for the duration of the current request to improve performance when the same content
+ /// item may be accessed multiple times. This is particularly useful in scenarios involving multiple languages or blocks.
+ ///
+ /// The unique identifier of the content item to retrieve.
+ /// The request-scoped cache used to store and retrieve content items for the duration of the current request.
+ /// The content service used to fetch the content item if it is not found in the cache.
+ /// The instance corresponding to the specified key, or null if no such content item exists.
+ [Obsolete("This method is available for support of request caching retrieved entities in derived property value editors. " +
+ "The intention is to supersede this with lazy loaded read locks, which will make this unnecessary. " +
+ "Scheduled for removal in Umbraco 19.")]
+ protected static IContent? GetAndCacheContentById(Guid key, IRequestCache requestCache, IContentService contentService)
+ {
+ if (requestCache.IsAvailable is false)
+ {
+ return contentService.GetById(key);
+ }
+
+ var cacheKey = string.Format(ContentCacheKeyFormat, key);
+ IContent? content = requestCache.GetCacheItem(cacheKey);
+ if (content is null)
+ {
+ content = contentService.GetById(key);
+ if (content is not null)
+ {
+ requestCache.Set(cacheKey, content);
+ }
+ }
+
+ return content;
+ }
+
+ ///
+ /// Adds the specified item to the request cache using its unique key.
+ ///
+ /// The content item to cache.
+ /// The request cache in which to store the content item.
+ [Obsolete("This method is available for support of request caching retrieved entities in derived property value editors. " +
+ "The intention is to supersede this with lazy loaded read locks, which will make this unnecessary. " +
+ "Scheduled for removal in Umbraco 19.")]
+ protected static void CacheContentById(IContent content, IRequestCache requestCache)
+ {
+ if (requestCache.IsAvailable is false)
+ {
+ return;
+ }
+
+ var cacheKey = string.Format(ContentCacheKeyFormat, content.Key);
+ requestCache.Set(cacheKey, content);
+ }
+
+ ///
+ /// Retrieves a instance by its unique identifier, using the provided request cache to avoid redundant
+ /// lookups within the same request.
+ ///
+ ///
+ /// This method caches media lookups for the duration of the current request to improve performance when the same media
+ /// item may be accessed multiple times. This is particularly useful in scenarios involving multiple languages or blocks.
+ ///
+ /// The unique identifier of the media item to retrieve.
+ /// The request-scoped cache used to store and retrieve media items for the duration of the current request.
+ /// The media service used to fetch the media item if it is not found in the cache.
+ /// The instance corresponding to the specified key, or null if no such media item exists.
+ [Obsolete("This method is available for support of request caching retrieved entities in derived property value editors. " +
+ "The intention is to supersede this with lazy loaded read locks, which will make this unnecessary. " +
+ "Scheduled for removal in Umbraco 19.")]
+ protected static IMedia? GetAndCacheMediaById(Guid key, IRequestCache requestCache, IMediaService mediaService)
+ {
+ if (requestCache.IsAvailable is false)
+ {
+ return mediaService.GetById(key);
+ }
+
+ var cacheKey = string.Format(MediaCacheKeyFormat, key);
+ IMedia? media = requestCache.GetCacheItem(cacheKey);
+
+ if (media is null)
+ {
+ media = mediaService.GetById(key);
+ if (media is not null)
+ {
+ requestCache.Set(cacheKey, media);
+ }
+ }
+
+ return media;
+ }
+
+ ///
+ /// Adds the specified item to the request cache using its unique key.
+ ///
+ /// The media item to cache.
+ /// The request cache in which to store the media item.
+ [Obsolete("This method is available for support of request caching retrieved entities in derived property value editors. " +
+ "The intention is to supersede this with lazy loaded read locks, which will make this unnecessary. " +
+ "Scheduled for removal in Umbraco 19.")]
+ protected static void CacheMediaById(IMedia media, IRequestCache requestCache)
+ {
+ if (requestCache.IsAvailable is false)
+ {
+ return;
+ }
+
+ var cacheKey = string.Format(MediaCacheKeyFormat, media.Key);
+ requestCache.Set(cacheKey, media);
+ }
+
+ ///
+ /// Determines whether the content item identified by the specified key is present in the request cache.
+ ///
+ /// The unique identifier for the content item to check for in the cache.
+ /// The request cache in which to look for the content item.
+ /// true if the content item is already cached in the request cache; otherwise, false.
+ [Obsolete("This method is available for support of request caching retrieved entities in derived property value editors. " +
+ "The intention is to supersede this with lazy loaded read locks, which will make this unnecessary. " +
+ "Scheduled for removal in Umbraco 19.")]
+ protected static bool IsContentAlreadyCached(Guid key, IRequestCache requestCache)
+ {
+ if (requestCache.IsAvailable is false)
+ {
+ return false;
+ }
+
+ var cacheKey = string.Format(ContentCacheKeyFormat, key);
+ return requestCache.GetCacheItem(cacheKey) is not null;
+ }
+
+ ///
+ /// Determines whether the media item identified by the specified key is present in the request cache.
+ ///
+ /// The unique identifier for the media item to check for in the cache.
+ /// The request cache in which to look for the media item.
+ /// true if the media item is already cached in the request cache; otherwise, false.
+ [Obsolete("This method is available for support of request caching retrieved entities in derived property value editors. " +
+ "The intention is to supersede this with lazy loaded read locks, which will make this unnecessary. " +
+ "Scheduled for removal in Umbraco 19.")]
+ protected static bool IsMediaAlreadyCached(Guid key, IRequestCache requestCache)
+ {
+ if (requestCache.IsAvailable is false)
+ {
+ return false;
+ }
+
+ var cacheKey = string.Format(MediaCacheKeyFormat, key);
+ return requestCache.GetCacheItem(cacheKey) is not null;
+ }
}
diff --git a/src/Umbraco.Core/PropertyEditors/ICacheReferencedEntities.cs b/src/Umbraco.Core/PropertyEditors/ICacheReferencedEntities.cs
new file mode 100644
index 0000000000..cf655a9167
--- /dev/null
+++ b/src/Umbraco.Core/PropertyEditors/ICacheReferencedEntities.cs
@@ -0,0 +1,19 @@
+namespace Umbraco.Cms.Core.PropertyEditors;
+
+///
+/// Optionally implemented by property editors, this defines a contract for caching entities that are referenced in block values.
+///
+[Obsolete("This interface is available for support of request caching retrieved entities in property value editors that implement it. " +
+ "The intention is to supersede this with lazy loaded read locks, which will make this unnecessary. " +
+ "Scheduled for removal in Umbraco 19.")]
+public interface ICacheReferencedEntities
+{
+ ///
+ /// Caches the entities referenced by the provided block data values.
+ ///
+ /// An enumerable collection of block values that may contain the entities to be cached.
+ [Obsolete("This method is available for support of request caching retrieved entities in derived property value editors. " +
+ "The intention is to supersede this with lazy loaded read locks, which will make this unnecessary. " +
+ "Scheduled for removal in Umbraco 19.")]
+ void CacheReferencedEntities(IEnumerable