diff --git a/src/Umbraco.PublishedCache.HybridCache/Persistence/DatabaseCacheRepository.cs b/src/Umbraco.PublishedCache.HybridCache/Persistence/DatabaseCacheRepository.cs
index 6923110a2b..fbdfe33758 100644
--- a/src/Umbraco.PublishedCache.HybridCache/Persistence/DatabaseCacheRepository.cs
+++ b/src/Umbraco.PublishedCache.HybridCache/Persistence/DatabaseCacheRepository.cs
@@ -14,7 +14,6 @@ using Umbraco.Cms.Infrastructure.HybridCache.Serialization;
using Umbraco.Cms.Infrastructure.Persistence;
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
using Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement;
-using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax;
using Umbraco.Cms.Infrastructure.Scoping;
using Umbraco.Extensions;
using static Umbraco.Cms.Core.Persistence.SqlExtensionsStatics;
@@ -61,7 +60,12 @@ internal sealed class DatabaseCacheRepository : RepositoryBase, IDatabaseCacheRe
///
public async Task DeleteContentItemAsync(int id)
- => await Database.ExecuteAsync("DELETE FROM cmsContentNu WHERE nodeId = @id", new { id });
+ {
+ Sql sql = Sql()
+ .Delete()
+ .Where(x => x.NodeId == id);
+ await Database.ExecuteAsync(sql);
+ }
///
public async Task RefreshContentAsync(ContentCacheNode contentCacheNode, PublishedState publishedState)
@@ -83,7 +87,10 @@ internal sealed class DatabaseCacheRepository : RepositoryBase, IDatabaseCacheRe
await OnRepositoryRefreshed(serializer, contentCacheNode, false);
break;
case PublishedState.Unpublishing:
- await Database.ExecuteAsync("DELETE FROM cmsContentNu WHERE nodeId = @id AND published = 1", new { id = contentCacheNode.Id });
+ Sql sql = Sql()
+ .Delete()
+ .Where(x => x.NodeId == contentCacheNode.Id && x.Published);
+ await Database.ExecuteAsync(sql);
break;
}
}
@@ -193,11 +200,11 @@ internal sealed class DatabaseCacheRepository : RepositoryBase, IDatabaseCacheRe
? SqlMediaSourcesSelect()
: throw new ArgumentOutOfRangeException(nameof(objectType), objectType, null);
- sql.InnerJoin("n")
- .On((n, c) => n.NodeId == c.ContentTypeId, "n", "umbracoContent")
- .Append(SqlObjectTypeNotTrashed(SqlContext, objectType))
- .WhereIn(x => x.UniqueId, keys,"n")
- .Append(SqlOrderByLevelIdSortOrder(SqlContext));
+ sql.InnerJoin("n")
+ .On((n, c) => n.NodeId == c.ContentTypeId, "n", "umbracoContent")
+ .Append(SqlObjectTypeNotTrashed(SqlContext, objectType))
+ .WhereIn(x => x.UniqueId, keys, "n")
+ .Append(SqlOrderByLevelIdSortOrder(SqlContext));
return GetContentNodeDtos(sql);
}
@@ -277,12 +284,13 @@ internal sealed class DatabaseCacheRepository : RepositoryBase, IDatabaseCacheRe
private async Task OnRepositoryRefreshed(IContentCacheDataSerializer serializer, ContentCacheNode content, bool preview)
{
-
ContentNuDto dto = GetDtoFromCacheNode(content, !preview, serializer);
+ string c(string s) => SqlSyntax.GetQuotedColumnName(s);
+
await Database.InsertOrUpdateAsync(
dto,
- "SET data = @data, dataRaw = @dataRaw, rv = rv + 1 WHERE nodeId = @id AND published = @published",
+ $"SET data = @data, {c("dataRaw")} = @dataRaw, rv = rv + 1 WHERE {c("nodeId")} = @id AND published = @published",
new
{
dataRaw = dto.RawData ?? Array.Empty(),
@@ -293,7 +301,7 @@ internal sealed class DatabaseCacheRepository : RepositoryBase, IDatabaseCacheRe
}
///
- /// Rebuilds the content database cache for documents.
+ /// Rebuilds the content database cache for documents by clearing and repopulating the cache with the latest document data.
///
///
/// Assumes content tree lock.
@@ -308,14 +316,7 @@ internal sealed class DatabaseCacheRepository : RepositoryBase, IDatabaseCacheRe
Guid contentObjectType = Constants.ObjectTypes.Document;
// Remove all - if anything fails the transaction will rollback.
- if (contentTypeIds.Count == 0)
- {
- DeleteForObjectType(contentObjectType);
- }
- else
- {
- DeleteForObjectTypeAndContentTypes(contentObjectType, contentTypeIds);
- }
+ RemoveByObjectType(contentObjectType, contentTypeIds);
// Insert back - if anything fails the transaction will rollback.
IQuery query = GetInsertQuery(contentTypeIds);
@@ -351,10 +352,10 @@ internal sealed class DatabaseCacheRepository : RepositoryBase, IDatabaseCacheRe
}
///
- /// Rebuilds the content database cache for media.
+ /// Rebuilds the content database cache for media by clearing and repopulating the cache with the latest media data.
///
///
- /// Assumes media tree lock.
+ /// Assumes content tree lock.
///
private void RebuildMediaDbCache(IContentCacheDataSerializer serializer, int groupSize, IReadOnlyCollection? contentTypeIds)
{
@@ -366,14 +367,7 @@ internal sealed class DatabaseCacheRepository : RepositoryBase, IDatabaseCacheRe
Guid mediaObjectType = Constants.ObjectTypes.Media;
// Remove all - if anything fails the transaction will rollback.
- if (contentTypeIds.Count == 0)
- {
- DeleteForObjectType(mediaObjectType);
- }
- else
- {
- DeleteForObjectTypeAndContentTypes(mediaObjectType, contentTypeIds);
- }
+ RemoveByObjectType(mediaObjectType, contentTypeIds);
// Insert back - if anything fails the transaction will rollback.
IQuery query = GetInsertQuery(contentTypeIds);
@@ -394,10 +388,10 @@ internal sealed class DatabaseCacheRepository : RepositoryBase, IDatabaseCacheRe
}
///
- /// Rebuilds the content database cache for members.
+ /// Rebuilds the content database cache for members by clearing and repopulating the cache with the latest member data.
///
///
- /// Assumes member tree lock.
+ /// Assumes content tree lock.
///
private void RebuildMemberDbCache(IContentCacheDataSerializer serializer, int groupSize, IReadOnlyCollection? contentTypeIds)
{
@@ -409,14 +403,7 @@ internal sealed class DatabaseCacheRepository : RepositoryBase, IDatabaseCacheRe
Guid memberObjectType = Constants.ObjectTypes.Member;
// Remove all - if anything fails the transaction will rollback.
- if (contentTypeIds.Count == 0)
- {
- DeleteForObjectType(memberObjectType);
- }
- else
- {
- DeleteForObjectTypeAndContentTypes(memberObjectType, contentTypeIds);
- }
+ RemoveByObjectType(memberObjectType, contentTypeIds);
// Insert back - if anything fails the transaction will rollback.
IQuery query = GetInsertQuery(contentTypeIds);
@@ -435,26 +422,39 @@ internal sealed class DatabaseCacheRepository : RepositoryBase, IDatabaseCacheRe
while (processed < total);
}
- private void DeleteForObjectType(Guid nodeObjectType) =>
- Database.Execute(
- @"
- DELETE FROM cmsContentNu
- WHERE cmsContentNu.nodeId IN (
- SELECT id FROM umbracoNode WHERE umbracoNode.nodeObjectType = @objType
- )",
- new { objType = nodeObjectType });
-
- private void DeleteForObjectTypeAndContentTypes(Guid nodeObjectType, IReadOnlyCollection contentTypeIds) =>
- Database.Execute(
- $@"
- DELETE FROM cmsContentNu
- WHERE cmsContentNu.nodeId IN (
- SELECT id FROM umbracoNode
- JOIN {Constants.DatabaseSchema.Tables.Content} ON {Constants.DatabaseSchema.Tables.Content}.nodeId=umbracoNode.id
- WHERE umbracoNode.nodeObjectType = @objType
- AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes)
- )",
- new { objType = nodeObjectType, ctypes = contentTypeIds });
+ private void RemoveByObjectType(Guid objectType, IReadOnlyCollection contentTypeIds)
+ {
+ // If the provided contentTypeIds collection is empty, remove all records for the provided object type.
+ Sql sql;
+ if (contentTypeIds.Count == 0)
+ {
+ sql = Sql()
+ .Delete()
+ .WhereIn(
+ x => x.NodeId,
+ Sql().Select(n => n.NodeId)
+ .From()
+ .Where(n => n.NodeObjectType == objectType));
+ Database.Execute(sql);
+ }
+ else
+ {
+ // Otherwise, if contentTypeIds are provided remove only those records that match the object type and one of the content types.
+ sql = Sql()
+ .Delete()
+ .WhereIn(
+ x => x.NodeId,
+ Sql()
+ .Select(n => n.NodeId)
+ .From()
+ .InnerJoin()
+ .On((n, c) => n.NodeId == c.NodeId)
+ .Where((n, c) =>
+ n.NodeObjectType == objectType &&
+ contentTypeIds.Contains(c.ContentTypeId)));
+ Database.Execute(sql);
+ }
+ }
private IQuery GetInsertQuery(IReadOnlyCollection contentTypeIds)
where TContent : IContentBase
@@ -484,7 +484,10 @@ internal sealed class DatabaseCacheRepository : RepositoryBase, IDatabaseCacheRe
var dto = new ContentNuDto
{
- NodeId = cacheNode.Id, Published = published, Data = serialized.StringData, RawData = serialized.ByteData,
+ NodeId = cacheNode.Id,
+ Published = published,
+ Data = serialized.StringData,
+ RawData = serialized.ByteData,
};
return dto;
@@ -560,7 +563,10 @@ internal sealed class DatabaseCacheRepository : RepositoryBase, IDatabaseCacheRe
var dto = new ContentNuDto
{
- NodeId = content.Id, Published = published, Data = serialized.StringData, RawData = serialized.ByteData,
+ NodeId = content.Id,
+ Published = published,
+ Data = serialized.StringData,
+ RawData = serialized.ByteData,
};
return dto;
@@ -633,39 +639,30 @@ internal sealed class DatabaseCacheRepository : RepositoryBase, IDatabaseCacheRe
private Sql SqlWhereNodeKey(ISqlContext sqlContext, Guid key)
{
- ISqlSyntaxProvider syntax = sqlContext.SqlSyntax;
-
SqlTemplate sqlTemplate = sqlContext.Templates.Get(
Constants.SqlTemplates.NuCacheDatabaseDataSource.WhereNodeKey,
builder =>
builder.Where(x => x.UniqueId == SqlTemplate.Arg("key")));
-
Sql sql = sqlTemplate.Sql(key);
return sql;
}
private Sql SqlOrderByLevelIdSortOrder(ISqlContext sqlContext)
{
- ISqlSyntaxProvider syntax = sqlContext.SqlSyntax;
-
SqlTemplate sqlTemplate = sqlContext.Templates.Get(
Constants.SqlTemplates.NuCacheDatabaseDataSource.OrderByLevelIdSortOrder, s =>
s.OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder));
-
Sql sql = sqlTemplate.Sql();
return sql;
}
private Sql SqlObjectTypeNotTrashed(ISqlContext sqlContext, Guid nodeObjectType)
{
- ISqlSyntaxProvider syntax = sqlContext.SqlSyntax;
-
SqlTemplate sqlTemplate = sqlContext.Templates.Get(
Constants.SqlTemplates.NuCacheDatabaseDataSource.ObjectTypeNotTrashedFilter, s =>
s.Where(x =>
x.NodeObjectType == SqlTemplate.Arg("nodeObjectType") &&
x.Trashed == SqlTemplate.Arg("trashed")));
-
Sql sql = sqlTemplate.Sql(nodeObjectType, false);
return sql;
}
@@ -681,7 +678,6 @@ internal sealed class DatabaseCacheRepository : RepositoryBase, IDatabaseCacheRe
.From()
.InnerJoin().On((left, right) => left.NodeId == right.NodeId)
.InnerJoin().On((left, right) => left.NodeId == right.NodeId));
-
Sql? sql = sqlTemplate.Sql();
if (joins != null)