Simplify UserDataManager and remove unused private methods

Removes unused private GetUserData and GetUserDataInternal methods.
Moves GetUserDataBatch to be an abstract interface method rather than
having a default implementation for clarity.
This commit is contained in:
Shadowghost
2026-01-17 13:10:00 +01:00
parent 1c1447362e
commit d3d4d37e82
2 changed files with 66 additions and 39 deletions

View File

@@ -177,53 +177,72 @@ namespace Emby.Server.Implementations.Library
};
}
private UserItemData? GetUserData(User user, Guid itemId, List<string> keys)
/// <inheritdoc />
public Dictionary<Guid, UserItemData> GetUserDataBatch(IReadOnlyList<BaseItem> items, User user)
{
var cacheKey = GetCacheKey(user.InternalId, itemId);
var result = new Dictionary<Guid, UserItemData>(items.Count);
var itemsNeedingQuery = new List<(BaseItem Item, List<string> Keys)>();
if (_cache.TryGet(cacheKey, out var data))
foreach (var item in items)
{
return data;
}
data = GetUserDataInternal(user.Id, itemId, keys);
if (data is null)
{
return new UserItemData()
var cacheKey = GetCacheKey(user.InternalId, item.Id);
if (_cache.TryGet(cacheKey, out var cachedData))
{
Key = keys[0],
};
}
return _cache.GetOrAdd(cacheKey, _ => data);
}
private UserItemData? GetUserDataInternal(Guid userId, Guid itemId, List<string> keys)
{
if (keys.Count == 0)
{
return null;
}
using var context = _repository.CreateDbContext();
var userData = context.UserData.AsNoTracking().Where(e => e.ItemId == itemId && keys.Contains(e.CustomDataKey) && e.UserId.Equals(userId)).ToArray();
if (userData.Length > 0)
{
var directDataReference = userData.FirstOrDefault(e => e.CustomDataKey == itemId.ToString("N"));
if (directDataReference is not null)
{
return Map(directDataReference);
result[item.Id] = cachedData;
}
else
{
var userData = item.UserData?.Where(e => e.UserId.Equals(user.Id)).Select(Map).FirstOrDefault();
if (userData is not null)
{
result[item.Id] = userData;
_cache.AddOrUpdate(cacheKey, userData);
}
else
{
var keys = item.GetUserDataKeys();
itemsNeedingQuery.Add((item, keys));
}
}
return Map(userData.First());
}
return new UserItemData
if (itemsNeedingQuery.Count == 0)
{
Key = keys.Last()!
};
return result;
}
// Build a single query for all missing items
var allItemIds = itemsNeedingQuery.Select(x => x.Item.Id).ToList();
var allKeys = itemsNeedingQuery.SelectMany(x => x.Keys).Distinct().ToList();
if (allKeys.Count > 0)
{
using var context = _repository.CreateDbContext();
var userDataArray = context.UserData
.AsNoTracking()
.Where(e => allItemIds.Contains(e.ItemId) && allKeys.Contains(e.CustomDataKey) && e.UserId.Equals(user.Id))
.ToArray();
var userDataByItem = userDataArray.GroupBy(e => e.ItemId).ToDictionary(g => g.Key, g => g.ToArray());
foreach (var (item, keys) in itemsNeedingQuery)
{
UserItemData userData;
if (userDataByItem.TryGetValue(item.Id, out var itemUserData) && itemUserData.Length > 0)
{
var directDataReference = itemUserData.FirstOrDefault(e => e.CustomDataKey == item.Id.ToString("N"));
userData = directDataReference is not null ? Map(directDataReference) : Map(itemUserData.First());
}
else
{
userData = new UserItemData { Key = keys.Count > 0 ? keys[0] : string.Empty };
}
result[item.Id] = userData;
var cacheKey = GetCacheKey(user.InternalId, item.Id);
_cache.AddOrUpdate(cacheKey, userData);
}
}
return result;
}
/// <summary>

View File

@@ -54,6 +54,14 @@ namespace MediaBrowser.Controller.Library
/// <returns>User data dto.</returns>
UserItemDataDto? GetUserDataDto(BaseItem item, User user);
/// <summary>
/// Gets user data for multiple items in a single batch operation.
/// </summary>
/// <param name="items">The items to get user data for.</param>
/// <param name="user">The user.</param>
/// <returns>A dictionary mapping item IDs to their user data.</returns>
Dictionary<Guid, UserItemData> GetUserDataBatch(IReadOnlyList<BaseItem> items, User user);
/// <summary>
/// Gets the user data dto.
/// </summary>