/// <summary> /// Gets multiple user profiles by their Ids. /// </summary> public override async Task <GetUserProfileResponse> GetUserProfile(GetUserProfileRequest request, ServerCallContext context) { var response = new GetUserProfileResponse(); if (request.UserIds == null || request.UserIds.Count == 0) { return(response); } // Since we're essentially doing a multi-get here, limit the number userIds (i.e. partition keys) to 20 in an attempt // to enforce some performance sanity. Anything larger and we might want to consider a different data model that doesn't // involve doing a multi-get if (request.UserIds.Count > 20) { var status = new Status(StatusCode.InvalidArgument, "Cannot get more than 20 user profiles at once"); throw new RpcException(status); } // Do some LINQ queries in parallel IEnumerable <Task <IEnumerable <LinqDtos.UserProfile> > > getProfilesTasks = request.UserIds.Select(uuid => _userProfileTable.Where(up => up.UserId == uuid.ToGuid()).ExecuteAsync()); IEnumerable <LinqDtos.UserProfile>[] profiles = await Task.WhenAll(getProfilesTasks).ConfigureAwait(false); // Get first profile returned for each query if not null and add to response response.Profiles.Add(profiles.Select(ps => ps.SingleOrDefault()).Where(p => p != null).Select(p => new UserProfile { UserId = p.UserId.ToUuid(), Email = p.EmailAddress, FirstName = p.FirstName, LastName = p.LastName })); return(response); }
/// <summary> /// Gets multiple user profiles by their Ids. /// </summary> public override async Task <GetUserProfileResponse> GetUserProfile(GetUserProfileRequest request, ServerCallContext context) { var response = new GetUserProfileResponse(); if (request.UserIds == null || request.UserIds.Count == 0) { return(response); } // Since we're essentially doing a multi-get here, limit the number userIds (i.e. partition keys) to 20 in an attempt // to enforce some performance sanity. Anything larger and we might want to consider a different data model that doesn't // involve doing a multi-get if (request.UserIds.Count > 20) { var status = new Status(StatusCode.InvalidArgument, "Cannot get more than 20 user profiles at once"); throw new RpcException(status); } // As an example, we'll do the multi-get at the CQL level using an IN() clause (i.e. let Cassandra handle it). For an example of // doing it at the driver level, see the VideoCatalog's GetVideoPreviews method // Build a parameterized CQL statement with an IN clause var parameterList = string.Join(", ", Enumerable.Repeat("?", request.UserIds.Count)); var cql = $"SELECT userid, firstname, lastname, email FROM users WHERE userid IN ({parameterList})"; var statement = new SimpleStatement(cql, request.UserIds.Select(uuid => uuid.ToGuid()).Cast <object>().ToArray()); // Execute and map to UserProfile object RowSet resultRows = await _session.ExecuteAsync(statement).ConfigureAwait(false); response.Profiles.Add(resultRows.Select(MapRowToUserProfile)); return(response); }