public static async Task <ScheduleViewItemsGroup> LoadAsync(Guid localAccountId, Guid semesterId, bool trackChanges = true, bool includeWeightCategories = true)
        {
            ScheduleViewItemsGroup answer;
            bool usedCached = false;

            // Find a cached match
            // Note that if the requester doesn't require weight categories, we'll ignore checking that includeWeightCategories matches,
            // since returning a cache that includes weight categories doesn't harm anything.
            lock (_cachedItems)
            {
                var cached = _cachedItems.FirstOrDefault(i =>
                                                         i.LocalAccountId == localAccountId &&
                                                         i.SemesterId == semesterId &&
                                                         (!includeWeightCategories || i._includeWeightCategories == includeWeightCategories));

                // If we'd like the changes tracked and we already have a matching cached
                if (trackChanges && cached != null)
                {
                    usedCached = true;
                    answer     = cached;
                }

                else
                {
                    // Otherwise, no cached or no change tracking requested, so load new
                    answer = new ScheduleViewItemsGroup(localAccountId, semesterId, trackChanges, includeWeightCategories);
                    answer._loadingTask = Task.Run(answer.LoadBlocking);

                    // If we're tracking changes, we'll add it to the cached
                    if (trackChanges)
                    {
                        _cachedItems.Add(answer);
                    }
                }
            }

            try
            {
                await answer._loadingTask;
                return(answer);
            }
            catch
            {
                if (usedCached)
                {
                    // If we were using cached and it previously failed to load,
                    // we remove it and try again
                    lock (_cachedItems)
                    {
                        _cachedItems.Remove(answer);
                    }
                }
                else
                {
                    throw;
                }
            }

            // We try to load again since we used cached and it failed previously
            return(await LoadAsync(localAccountId, semesterId, trackChanges : trackChanges, includeWeightCategories : includeWeightCategories));
        }
        protected async Task LoadBlocking(Guid examId)
        {
            var dataStore = await GetDataStore();

            if (dataStore == null)
            {
                throw new NullReferenceException("Account doesn't exist");
            }

            DataItemMegaItem dataItem;

            // We need ALL classes loaded, including their schedules, and their weight categories.
            // Might as well just use ScheduleViewItemsGroup therefore.

            Guid semesterId;
            Guid classId = Guid.Empty;

            using (await Locks.LockDataForReadAsync("BaseSingleItemViewItemsGroup.LoadBlocking"))
            {
                dataItem = dataStore.TableMegaItems.FirstOrDefault(i => i.Identifier == examId);
                if (dataItem == null)
                {
                    TelemetryExtension.Current?.TrackEvent("Error_LoadSingleItem_CouldNotFind", new Dictionary <string, string>()
                    {
                        { "ItemId", examId.ToString() }
                    });

                    // Leave the Item set to null
                    return;
                }

                if (dataItem.MegaItemType == PowerPlannerSending.MegaItemType.Task || dataItem.MegaItemType == PowerPlannerSending.MegaItemType.Event)
                {
                    semesterId = dataItem.UpperIdentifier;
                    classId    = dataItem.UpperIdentifier;
                }
                else
                {
                    var dataClass = dataStore.TableClasses.FirstOrDefault(i => i.Identifier == dataItem.UpperIdentifier);
                    if (dataClass == null)
                    {
                        throw new NullReferenceException("Class not found. Item id " + examId);
                    }
                    semesterId = dataClass.UpperIdentifier;
                    classId    = dataClass.Identifier;
                }
            }

            _scheduleViewItemsGroup = await ScheduleViewItemsGroup.LoadAsync(LocalAccountId, semesterId : semesterId, trackChanges : trackChanges, includeWeightCategories : true);

            // Grab the class for the item
            ViewItemClass viewClass;

            if (dataItem.MegaItemType == PowerPlannerSending.MegaItemType.Task || dataItem.MegaItemType == PowerPlannerSending.MegaItemType.Event)
            {
                viewClass = _scheduleViewItemsGroup.Semester.NoClassClass;
            }
            else
            {
                viewClass = _scheduleViewItemsGroup.Semester.Classes.FirstOrDefault(i => i.Identifier == classId);
                if (viewClass == null)
                {
                    throw new NullReferenceException("ViewItemClass not found. Item id " + examId);
                }
            }

            // And create the item
            Item = CreateItem(dataItem, viewClass);
        }