aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.LocalMetadata/Savers
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.LocalMetadata/Savers')
-rw-r--r--MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs55
1 files changed, 38 insertions, 17 deletions
diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
index 025a815247..b0f51aec71 100644
--- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
@@ -6,7 +7,6 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
-using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
@@ -467,41 +467,62 @@ namespace MediaBrowser.LocalMetadata.Savers
}
/// <summary>
- /// ADd linked children.
+ /// Add linked children.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="writer">The xml writer.</param>
/// <param name="pluralNodeName">The plural node name.</param>
/// <param name="singularNodeName">The singular node name.</param>
/// <returns>The task object representing the asynchronous operation.</returns>
- private static async Task AddLinkedChildren(Folder item, XmlWriter writer, string pluralNodeName, string singularNodeName)
+ private async Task AddLinkedChildren(Folder item, XmlWriter writer, string pluralNodeName, string singularNodeName)
{
- var items = item.LinkedChildren
+ var linkedChildren = item.LinkedChildren
.Where(i => i.Type == LinkedChildType.Manual)
.ToList();
- if (items.Count == 0)
+ if (linkedChildren.Count == 0)
{
return;
}
- await writer.WriteStartElementAsync(null, pluralNodeName, null).ConfigureAwait(false);
+ // Batch-resolve all ItemIds to paths in a single query to avoid an N+1 round-trip per linked child
+ var idsToResolve = new HashSet<Guid>();
+ foreach (var link in linkedChildren)
+ {
+ if (link.ItemId.HasValue && !link.ItemId.Value.Equals(Guid.Empty))
+ {
+ idsToResolve.Add(link.ItemId.Value);
+ }
+ }
- foreach (var link in items)
+ Dictionary<Guid, string?>? pathById = null;
+ if (idsToResolve.Count > 0)
{
- if (!string.IsNullOrWhiteSpace(link.Path) || !string.IsNullOrWhiteSpace(link.LibraryItemId))
+ var batched = LibraryManager.GetItemList(new InternalItemsQuery
{
- await writer.WriteStartElementAsync(null, singularNodeName, null).ConfigureAwait(false);
- if (!string.IsNullOrWhiteSpace(link.Path))
- {
- await writer.WriteElementStringAsync(null, "Path", null, link.Path).ConfigureAwait(false);
- }
+ ItemIds = [.. idsToResolve]
+ });
+ pathById = new Dictionary<Guid, string?>(batched.Count);
+ foreach (var batchedItem in batched)
+ {
+ pathById[batchedItem.Id] = batchedItem.Path;
+ }
+ }
- if (!string.IsNullOrWhiteSpace(link.LibraryItemId))
- {
- await writer.WriteElementStringAsync(null, "ItemId", null, link.LibraryItemId).ConfigureAwait(false);
- }
+ await writer.WriteStartElementAsync(null, pluralNodeName, null).ConfigureAwait(false);
+
+ foreach (var link in linkedChildren)
+ {
+ string? path = null;
+ if (pathById is not null && link.ItemId.HasValue && pathById.TryGetValue(link.ItemId.Value, out var resolvedPath))
+ {
+ path = resolvedPath;
+ }
+ if (!string.IsNullOrWhiteSpace(path))
+ {
+ await writer.WriteStartElementAsync(null, singularNodeName, null).ConfigureAwait(false);
+ await writer.WriteElementStringAsync(null, "Path", null, path).ConfigureAwait(false);
await writer.WriteEndElementAsync().ConfigureAwait(false);
}
}