IQueryable a wcześniejszy dostęp do danych

0

Muszę wykonać page'owanie, jednak dla każdego zalogowanego użytkownika jest inna widoczność dokumentów, w zależności od ustawionych na nich uprawnień. Wykonałem więc taką metodę:

        private void ConstraintDocumentsToUserRole(ref IQueryable<OtherDocument> otherDocumentQuery)
        {
            var user = _userRepository.GetAllIncluding(e => e.Roles).FirstOrDefault(e => e.Id == AbpSession.UserId.Value);
            if (user == null)
            {
                throw new VZeroUserFriendlyException(L("UserNotFound"));
            }
            if (user.UserRole != AppUserRole.MasterAdmin && user.UserRole != AppUserRole.Admin)
            {
                otherDocumentQuery = otherDocumentQuery.Where(e => HasUserAccessRights(e, user))
            }
        }

        private bool HasUserAccessRights(OtherDocument otherDocument, AbpUserBase user)
        {
            if (!otherDocument.ShareType.HasValue)
            {
                return false;
            }

            switch (otherDocument.ShareType.Value)
            {
                case ShareType.All:
                    return true;
                case ShareType.Organizations:
                    return otherDocument.AccessRights.Any(f => f.TenantId == f.UserId) &&
                           (otherDocument.Role.Name == AppConsts.PublicRoleName ||
                            user.Roles.Any(f => otherDocument.RoleId == f.RoleId));
                case ShareType.Users:
                    return otherDocument.AccessRights.Any(f => f.UserId == user.Id) &&
                           (otherDocument.Role.Name == AppConsts.PublicRoleName ||
                            user.Roles.Any(f => otherDocument.RoleId == f.RoleId));
                default: return false;
            }
        }

Kiedy jednak przychodzi do pobrania AccessRights, jest ono puste, jako że operujemy tylko na ekspresji sql, nic wcześniej nie zwracając. Ma ktoś może pomysł, jak to obejść bez potrzeby pobierania wcześniej wszystkich danych? Może warto po prostu zrobić procedurę po stronie sql, przekazując potrzebne parametry?

0

Przekazuj do HasUserAccessRights całe IQueryable i tam sprawdzaj warunki w Where, co w tym rodzaju:

private IQueryable<OtherDocument> HasUserAccessRights(IQueryable<OtherDocument> otherDocuments, AbpUserBase user)
{
    return otherDocuments.Where(doc => doc.ShareType == ShareType.All ||
        (doc.ShareType == ShareType.Organizations && 
        doc.AccessRights.Any(f => f.TenantId == f.UserId) &&
                   (doc.Role.Name == AppConsts.PublicRoleName ||
                    user.Roles.Any(f => doc.RoleId == f.RoleId))) ||
        doc.ShareType == ShareType.Users && (doc.AccessRights.Any(f => f.UserId == user.Id) &&
                   (doc.Role.Name == AppConsts.PublicRoleName ||
                    user.Roles.Any(f => doc.RoleId == f.RoleId)))
}

Jeśli potrzebujesz czegoś bardziej dynamicznego to możesz się pokusić o użycie Expression i sklejanie z nich warunków.
Domyślam się, że to EF Core? EF Core ma automatyczny fallback do wykonania zapytania w aplikacji jeśli nie potrafi przetłumaczyć czegoś do SQLa, zapewne tak się działo w przypadku Twojej metody HasUserAccessRights.

1 użytkowników online, w tym zalogowanych: 0, gości: 1