From b24ce17193082816658766a7daebb213d33fee15 Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Mon, 14 Nov 2022 10:18:09 -0500 Subject: [PATCH] [PS-1806] Fix EF CollectionRepository `GetManyByUserId` (#2409) * Rewrite ReadOnly and HidePasswords * Rewrote them to generate a CASE statement similar to T-SQL * Rewrite Grouping Expression * Use multiple groups just like T-SQL * Run it all on the database instead of in memory * Fix linter --- .../Repositories/CollectionRepository.cs | 26 +++++++++---------- .../Queries/UserCollectionDetailsQuery.cs | 10 +++++-- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/Infrastructure.EntityFramework/Repositories/CollectionRepository.cs b/src/Infrastructure.EntityFramework/Repositories/CollectionRepository.cs index 712cd25b2f..38ad52deda 100644 --- a/src/Infrastructure.EntityFramework/Repositories/CollectionRepository.cs +++ b/src/Infrastructure.EntityFramework/Repositories/CollectionRepository.cs @@ -131,19 +131,19 @@ public class CollectionRepository : Repository c.Id) - .Select(g => new CollectionDetails - { - Id = g.Key, - OrganizationId = g.FirstOrDefault().OrganizationId, - Name = g.FirstOrDefault().Name, - ExternalId = g.FirstOrDefault().ExternalId, - CreationDate = g.FirstOrDefault().CreationDate, - RevisionDate = g.FirstOrDefault().RevisionDate, - ReadOnly = g.Min(c => c.ReadOnly), - HidePasswords = g.Min(c => c.HidePasswords) - }).ToList(); + return await (from c in new UserCollectionDetailsQuery(userId).Run(dbContext) + group c by new { c.Id, c.OrganizationId, c.Name, c.CreationDate, c.RevisionDate, c.ExternalId } into collectionGroup + select new CollectionDetails + { + Id = collectionGroup.Key.Id, + OrganizationId = collectionGroup.Key.OrganizationId, + Name = collectionGroup.Key.Name, + CreationDate = collectionGroup.Key.CreationDate, + RevisionDate = collectionGroup.Key.RevisionDate, + ExternalId = collectionGroup.Key.ExternalId, + ReadOnly = collectionGroup.Min(c => c.ReadOnly), + HidePasswords = collectionGroup.Min(c => c.HidePasswords), + }).ToListAsync(); } } diff --git a/src/Infrastructure.EntityFramework/Repositories/Queries/UserCollectionDetailsQuery.cs b/src/Infrastructure.EntityFramework/Repositories/Queries/UserCollectionDetailsQuery.cs index a003bef86c..00083472d8 100644 --- a/src/Infrastructure.EntityFramework/Repositories/Queries/UserCollectionDetailsQuery.cs +++ b/src/Infrastructure.EntityFramework/Repositories/Queries/UserCollectionDetailsQuery.cs @@ -10,6 +10,7 @@ public class UserCollectionDetailsQuery : IQuery { _userId = userId; } + public virtual IQueryable Run(DatabaseContext dbContext) { var query = from c in dbContext.Collections @@ -44,6 +45,8 @@ public class UserCollectionDetailsQuery : IQuery o.Enabled && (ou.AccessAll || cu.CollectionId != null || g.AccessAll || cg.CollectionId != null) select new { c, ou, o, cu, gu, g, cg }; +#pragma warning disable IDE0075 + // I want to leave the ReadOnly and HidePasswords the way they are because it helps show the exact logic we are trying to replicate return query.Select(x => new CollectionDetails { Id = x.c.Id, @@ -52,8 +55,11 @@ public class UserCollectionDetailsQuery : IQuery ExternalId = x.c.ExternalId, CreationDate = x.c.CreationDate, RevisionDate = x.c.RevisionDate, - ReadOnly = !x.ou.AccessAll || !x.g.AccessAll || (x.cu.ReadOnly || x.cg.ReadOnly), - HidePasswords = !x.ou.AccessAll || !x.g.AccessAll || (x.cu.HidePasswords || x.cg.HidePasswords), + ReadOnly = x.ou.AccessAll || x.g.AccessAll || ((x.cu != null ? x.cu.ReadOnly : (bool?)null) ?? (x.cg != null ? x.cg.ReadOnly : (bool?)null) ?? false) ? false : true, + HidePasswords = x.ou.AccessAll || x.g.AccessAll || ((x.cu != null ? x.cu.HidePasswords : (bool?)null) ?? (x.cg != null ? x.cg.HidePasswords : (bool?)null) ?? false) ? false : true, }); +#pragma warning restore IDE0075 } + + }