From 5c48b5c90e8037e9b9ea4b4c59d4e376a20590d9 Mon Sep 17 00:00:00 2001 From: Jake Mannens Date: Thu, 24 Aug 2023 14:23:34 +1000 Subject: Removed EFCore lazy-loading proxies --- HBContext.cs | 1 - Media.cs | 8 ++-- Pages/Gallery.razor | 11 ++++- Pages/TagDefinitions.razor | 1 + Pages/ViewMedia.razor | 15 ++++-- Services/MediaService.cs | 15 ++++-- Services/TagService.cs | 117 +++++++++++++++++++++++++++++++++++---------- 7 files changed, 125 insertions(+), 43 deletions(-) diff --git a/HBContext.cs b/HBContext.cs index 74c040c..d0cd26f 100644 --- a/HBContext.cs +++ b/HBContext.cs @@ -19,7 +19,6 @@ public class HBContext : DbContext { this.config = config; protected override void OnConfiguring(DbContextOptionsBuilder options) { - options.UseLazyLoadingProxies(); options.UseNpgsql(config.DbConnectionString); #if DEBUG diff --git a/Media.cs b/Media.cs index 2e06dbf..56d5f41 100644 --- a/Media.cs +++ b/Media.cs @@ -14,12 +14,12 @@ public class Media : HBObject { public virtual List UploadedFiles { get; set; } = new(); public bool IsIngest => Tags - .Select(t => t.TagDefinition) - .Any(td => td.Guid == HBContext.IngestTag); + .Select(t => t.TagDefinition.Guid) + .Contains(HBContext.IngestTag); public bool IsNsfw => Tags - .Select(t => t.TagDefinition) - .Any(td => td.Guid == HBContext.NsfwTag); + .Select(t => t.TagDefinition.Guid) + .Contains(HBContext.NsfwTag); public string? DisplayName { get { diff --git a/Pages/Gallery.razor b/Pages/Gallery.razor index 695f2f7..62d1a27 100644 --- a/Pages/Gallery.razor +++ b/Pages/Gallery.razor @@ -40,6 +40,8 @@ using var db = dbFactory.CreateDbContext(); IEnumerable media = db.Media + .Include(m => m.Tags) + .ThenInclude(t => t.TagDefinition) .OrderByDescending(m => m.ObjectId) .ToArray(); @@ -53,10 +55,15 @@ .Where(m => m.IsIngest); // Filter both NSFW AND ingest images if we're not showing NSFW - if(!userState.ShowNsfw) + if(!userState.ShowNsfw) { + var nsfwTags = tagService.TagsThatImply(HBContext.NsfwTag) + .Select(td => td.Guid) + .ToArray(); media = media .AsEnumerable() - .Where(m => !m.IsNsfw && !m.IsIngest); + .Where(m => !m.Tags.Select(t => t.TagDefinition.Guid).Intersect(nsfwTags).Any()) + .Where(m => !m.IsIngest); + } Media = media.ToArray(); } diff --git a/Pages/TagDefinitions.razor b/Pages/TagDefinitions.razor index 7d9c3a1..455c4ac 100644 --- a/Pages/TagDefinitions.razor +++ b/Pages/TagDefinitions.razor @@ -101,6 +101,7 @@ private TagDefinition[] tagDefinitions => dbFactory.CreateDbContext().TagDefinitions + .Include(td => td.ImplicitTags) .Where(td => td.Source == TagSource.UserTag) .OrderBy(td => td.Namespace) .ThenBy(td => td.Name) diff --git a/Pages/ViewMedia.razor b/Pages/ViewMedia.razor index fe73c7d..52300e3 100644 --- a/Pages/ViewMedia.razor +++ b/Pages/ViewMedia.razor @@ -106,9 +106,15 @@ protected override void OnInitialized() { db = dbFactory.CreateDbContext(); - media = db.Media.First(m => m.Guid == MediaId); - if(media is null) - throw new ArgumentException("Media not found!"); + LoadMedia(); + } + + private void LoadMedia() { + media = db.Media + .Include(m => m.Tags) + .ThenInclude(t => t.TagDefinition) + .Include(m => m.UploadedFiles) + .First(m => m.Guid == MediaId); title = media.DisplayName ?? "Media View"; } @@ -121,9 +127,8 @@ private void SetIngest(bool ingest) { mediaService.SetIngest(media, ingest); - // TODO: fix this hacky method of reloading the media entity db.Entry(media).State = EntityState.Detached; - media = db.Media.First(m => m.Guid == media.Guid); + LoadMedia(); StateHasChanged(); } diff --git a/Services/MediaService.cs b/Services/MediaService.cs index aa733c3..1fc74cd 100644 --- a/Services/MediaService.cs +++ b/Services/MediaService.cs @@ -19,14 +19,19 @@ public class MediaService : IMediaService { public void SetIngest(Media media, bool ingest) { using var db = dbFactory.CreateDbContext(); - media = db.Media.First(m => m.Guid == media.Guid); + media = db.Media + .Include(m => m.Tags) + .ThenInclude(t => t.TagDefinition) + .First(m => m.Guid == media.Guid); var ingestTag = db.TagDefinitions .First(td => td.Guid == HBContext.IngestTag); - if(ingest) - media.Tags.Add(new(ingestTag)); - else - media.Tags.RemoveAll(t => t.TagDefinition.Guid == ingestTag.Guid); + if(ingest) { + if(!media.Tags.Select(t => t.TagDefinition.Guid).Contains(HBContext.IngestTag)) + media.Tags.Add(new(ingestTag)); + } else { + media.Tags.RemoveAll(t => t.TagDefinition.Guid == HBContext.IngestTag); + } db.SaveChanges(); } diff --git a/Services/TagService.cs b/Services/TagService.cs index 860103b..a0fd19e 100644 --- a/Services/TagService.cs +++ b/Services/TagService.cs @@ -26,6 +26,8 @@ public interface ITagService { public (TagDefinition tagDefinition, bool isImplicit)[] GetAllTags(Guid obj); public (TagDefinition tagDefinition, bool isImplicit)[] GetAllTags(HBObject obj); public (TagDefinition tagDefinition, bool isImplicit)[] GetAllTags(TagDefinition tagDef); + public TagDefinition[] TagsThatImply(Guid tagDef); + public TagDefinition[] TagsThatImply(TagDefinition tagDef); } public class TagService : ITagService { @@ -40,6 +42,8 @@ public class TagService : ITagService { var tag = db.TagDefinitions.First(td => td.Guid == tagDef); db.Objects + .Include(o => o.Tags) + .ThenInclude(t => t.TagDefinition) .Where(o => !o.Tags.Select(t => t.TagDefinition.Guid).Contains(tagDef)) .FirstOrDefault(o => o.Guid == obj)? .Tags @@ -54,7 +58,11 @@ public class TagService : ITagService { public void RemoveTag(Guid obj, Guid tagDef) { using var db = dbFactory.CreateDbContext(); - db.Objects.First(o => o.Guid == obj).Tags + db.Objects + .Include(o => o.Tags) + .ThenInclude(t => t.TagDefinition) + .First(o => o.Guid == obj) + .Tags .RemoveAll(t => t.TagDefinition.Guid == tagDef); db.SaveChanges(); @@ -67,7 +75,9 @@ public class TagService : ITagService { using var db = dbFactory.CreateDbContext(); using var transaction = db.Database.BeginTransaction(); - var tag = db.TagDefinitions.First(td => td.Guid == tagDef); + var tag = db.TagDefinitions + .Include(td => td.ImplicitTags) + .First(td => td.Guid == tagDef); tag.ImplicitTags.RemoveAll(td => !implicitTagDefs.Contains(td.Guid)); tag.ImplicitTags.AddRange( @@ -87,7 +97,9 @@ public class TagService : ITagService { public void AddImplicitTag(Guid tagDef, Guid implicitTagDef) { using var db = dbFactory.CreateDbContext(); - var tag = db.TagDefinitions.First(td => td.Guid == tagDef); + var tag = db.TagDefinitions + .Include(td => td.ImplicitTags) + .First(td => td.Guid == tagDef); var implicitTag = db.TagDefinitions.First(td => td.Guid == implicitTagDef); tag.ImplicitTags.Add(implicitTag); @@ -100,7 +112,9 @@ public class TagService : ITagService { public void RemoveImplicitTag(Guid tagDef, Guid implicitTagDef) { using var db = dbFactory.CreateDbContext(); - var tag = db.TagDefinitions.First(td => td.Guid == tagDef); + var tag = db.TagDefinitions + .Include(td => td.ImplicitTags) + .First(td => td.Guid == tagDef); tag.ImplicitTags.RemoveAll(td => td.Guid == implicitTagDef); db.SaveChanges(); @@ -130,7 +144,9 @@ public class TagService : ITagService { using var transaction = db.Database.BeginTransaction(); db.Tags.RemoveRange( - db.Tags.Where(t => t.TagDefinition.Guid == tagDef)); + db.Tags + .Include(t => t.TagDefinition) + .Where(t => t.TagDefinition.Guid == tagDef)); db.TagDefinitions.Remove(tag); db.SaveChanges(); @@ -156,48 +172,97 @@ public class TagService : ITagService { public void UpdateTagDefinition(TagDefinition tagDef, string name, string? @namespace) => UpdateTagDefinition(tagDef.Guid, name, @namespace); - public (TagDefinition tagDefinition, bool isImplicit)[] GetAllTags(Guid obj) { + private (TagDefinition tagDefinition, bool isImplicit)[] GetAllTags(IEnumerable tagDefs) { using var db = dbFactory.CreateDbContext(); - var @object = db.Objects.First(o => o.Guid == obj); - var guids = @object.Tags.Select(t => t.TagDefinition.Guid); + var tagGuids = tagDefs + .Select(td => td.Guid) + .ToArray(); + + // Query all tag definitions + var allTags = db.TagDefinitions + .Include(td => td.ImplicitTags) + .ToArray(); + + var tags = new List( + allTags.IntersectBy( + tagGuids, + td => td.Guid)); + + while(true) { + var toAdd = tags + .SelectMany(td => td.ImplicitTags) + .ExceptBy(tags.Select(td => td.Guid), td => td.Guid) + .ToArray(); + + if(toAdd.Count() == 0) + break; + + tags.AddRange(toAdd); + } + + return tags + .Select(td => new ValueTuple(td, !tagGuids.Contains(td.Guid))) + .ToArray(); + } + + public (TagDefinition tagDefinition, bool isImplicit)[] GetAllTags(Guid obj) { + using var db = dbFactory.CreateDbContext(); - return GetTagRecursive(@object.Tags.Select(t => t.TagDefinition)) - .Select(td => new ValueTuple(td, !guids.Contains(td.Guid))) + // Query a list of tag GUIDs for this object + var tags = db.Objects + .Include(o => o.Tags) + .ThenInclude(t => t.TagDefinition) + .First(o => o.Guid == obj) + .Tags + .Select(t => t.TagDefinition) .ToArray(); + + return GetAllTags(tags); } + public (TagDefinition tagDefinition, bool isImplicit)[] GetAllTags(HBObject obj) => GetAllTags(obj.Guid); public (TagDefinition tagDefinition, bool isImplicit)[] GetAllTags(TagDefinition tagDef) { using var db = dbFactory.CreateDbContext(); - var tag = db.TagDefinitions.First(td => td.Guid == tagDef.Guid); - - return GetTagRecursive(tag.ImplicitTags) - .Select(td => new ValueTuple(td, !tag.ImplicitTags.Select(it => it.Guid).Contains(td.Guid))) + var tags = db.TagDefinitions + .Include(td => td.ImplicitTags) + .First(td => td.Guid == tagDef.Guid) + .ImplicitTags .ToArray(); + + return GetAllTags(tags); } - private List GetTagRecursive(IEnumerable tagDefs) { - var tags = new List(tagDefs); + public TagDefinition[] TagsThatImply(Guid tagDef) { + using var db = dbFactory.CreateDbContext(); - List? toProcessNext = null; + var tagDefs = db.TagDefinitions + .Include(td => td.ImplicitTags) + .ToArray(); - while(true) { - toProcessNext = (toProcessNext ?? tags) - .SelectMany(td => td.ImplicitTags) - .Where(td => !tags.Select(td => td.Guid).Contains(td.Guid)) - .DistinctBy(td => td.Guid) - .ToList(); + var tags = new List() { + db.TagDefinitions.First(td => td.Guid == tagDef) + }; - tags.AddRange(toProcessNext); + while(true) { + var toAdd = tagDefs + .Where(td => td.ImplicitTags.Select(it => it.Guid).Intersect(tags.Select(td => td.Guid)).Any()) + .ExceptBy(tags.Select(td => td.Guid), td => td.Guid) + .ToArray(); - if(toProcessNext.Count() == 0) + if(toAdd.Count() == 0) break; + + tags.AddRange(toAdd); } - return tags; + return tags.ToArray(); } + + public TagDefinition[] TagsThatImply(TagDefinition tagDef) => + TagsThatImply(tagDef.Guid); } -- cgit v1.3