понедельник, 8 апреля 2013 г.

Azure Mobile Service - Как получить все данные?

Разбираясь с Windows Azure Mobile Service, наткнулся на очень интересный нюанс: при запросе данных с помощью метода IMobileServiceTable<T>.ToListAsync (и других аналогичных методов соответствующего интерфейса) количество возвращаемых записей (по умолчанию) не превышает 50! (Более подробно можно прочитать здесь).

Example:
    var mobileServiceTable = App.MobileService.GetTable<SomeObject>();
    var cloudList = await mobileServiceTable.OrderBy(obj => obj.SomeProperty).ToListAsync();
    var count = 0;
    foreach (var item in cloudList)
    {
        count++;
    }
    Debug.WriteLine(count);
Если кол-во объектов SomeObject > 50, count все равно будет равен 50

То есть для того, чтобы получить 150 записей, нужно использовать метод IMobileServiceTable<T>.Take и непосредственно указывать нужное количество. А если это количество заранее не известно? К примеру, нужно синхронизировать базу данных в облаке с локальной копией.
Чтобы узнать общее количество записей, потребуется интерфейс ITotalCountProvider, используя который можно получить количество всех записей, возвращаемых запросом.

Example:
    var mobileServiceTable = App.MobileService.GetTable<SomeObject>();
    var cloudList = await mobileServiceTable.OrderBy(obj => obj.SomeProperty).IncludeTotalCount().ToListAsync();
    var countProvider = cloudList as ITotalCountProvider;
    Debug.WriteLine(countProvider.TotalCount);
    var count = 0;
    foreach (var item in cloudList)
    {
        count++;
    }
    Debug.WriteLine(count);

Однако, это не решает проблему, так как переменная count будет по прежнему равно 50 (хотя TotalCount = 150).


Чтобы решить данную проблему я сделал несколько вспомогательных методов, которые позволяют получить все записи из Mobile Service:

MobileServiceTableExtensions.cs:
    public static class MobileServiceTableExtensions
    {
        public static async Task<IEnumerable<T>> GetAllAsync<T>(this IMobileServiceTable<T> mobileServiceTable, Int32 count = 50)
        {
            return await GetAll(mobileServiceTable, count);
        }

        public static async Task<IEnumerable<T>> WhereAsync<T>(this IMobileServiceTable<T> mobileServiceTable, Expression<Func<T, bool>> predicate, Int32 count = 50)
        {
            return await Where(mobileServiceTable, predicate, count);
        }

        private static async Task<IEnumerable<T>> GetAll<T>(this IMobileServiceTable<T> mobileServiceTable, Int32 count)
        {
            var list = new List<T>();
            var items = await mobileServiceTable.Take(count).IncludeTotalCount().ToEnumerableAsync();
            list.AddRange(items);
            var countProvider = items as ITotalCountProvider;
            if (countProvider != null)
            {
                var current = count;
                while (current < countProvider.TotalCount)
                {
                    items = await mobileServiceTable.Skip(current).ToEnumerableAsync();
                    list.AddRange(items);
                    current += count;
                }
            }
            return list;
        }

        private static async Task<IEnumerable<T>> Where<T>(this IMobileServiceTable<T> mobileServiceTable, Expression<Func<T, bool>> predicate, Int32 count)
        {
            var list = new List<T>();
            var items = await mobileServiceTable.Where(predicate).Take(count).IncludeTotalCount().ToEnumerableAsync();
            list.AddRange(items);
            var countProvider = items as ITotalCountProvider;
            if (countProvider != null)
            {
                var current = count;
                while (current < countProvider.TotalCount)
                {
                    items = await mobileServiceTable.Where(predicate).Skip(current).ToEnumerableAsync();
                    list.AddRange(items);
                    current += count;
                }
            }
            return list;
        }
    }

Теперь, используя эти методы расширения, я могу достаточно просто получить список всех записей:

Example:
    var mobileServiceTable = App.MobileService.GetTable<SomeObject>();
    var cloudList = await mobileServiceTable.GetAllAsync();
    var count = 0;
    foreach (var item in cloudList)
    {
        count++;
    }
    Debug.WriteLine(count);
Переменная count равна реальному количеству записей

P.S. Пока писал статью, нашел похожий пост на MSDN.

Комментариев нет:

Отправить комментарий