Сохранение данных локально и удаленно (синхронизация) - PullRequest
3 голосов
/ 02 апреля 2011

Когда данные введены, их в конечном итоге необходимо сохранить на сервере удаленно.Я хочу, чтобы приложение работало, если в то же время отсутствует подключение для передачи данных, поэтому мне нужно также сохранять все локально на телефоне.Затем приложение может синхронизироваться с сервером, когда оно получает соединение.

Это поднимает небольшую проблему.Я привык сохранять все на сервере, а затем возвращать записи с идентификаторами, сгенерированными для них с сервера.Если соединение отсутствует, приложение будет сохранять данные локально на телефон, но не на сервер.При синхронизации с сервером я не вижу способа узнать, когда возвращается запись с локальной записью, с которой она связана.Не достаточно уникальных данных, чтобы понять это.

Каков наилучший способ справиться с этим?

Один из способов, которым я думал, - это изменить идентификатор записей наGUID и позвольте телефону установить идентификатор.Таким образом, все записи будут иметь локальный идентификатор, а при сохранении на сервере он все равно должен быть уникальным.

Я хотел бы знать, что делали другие люди, что работает и чтоне из опыта.

Ответы [ 2 ]

2 голосов
/ 03 апреля 2011

Вот как мы сделали с первым приложением для Windows Phone 7, которое закончилось несколько дней назад с моим другом. Возможно, это не лучшее решение, но до дополнительного рефакторинга оно работает просто отлично. Это приложение для веб-приложения, такого как mint.com, под названием slamarica .

Если у нас есть функция сохранения транзакции, мы сначала проверяем, есть ли у нас подключение к Интернету.

        // Check if application is in online or in offline mode 
        if (NetworkDetector.IsOnline)
        {
            // Save through REST API
            _transactionBl.AddTransaction(_currentTransaction);
        }
        else
        {
            // Save to phone database
            SaveTransactionToPhone(_currentTransaction);
        }

Если транзакция успешно сохраняется через REST, она отвечает объектом транзакции, а затем мы сохраняем ее в локальной базе данных. Если не удалось сохранить REST, мы сохраняем данные в локальной базе данных.

 private void OnTransactionSaveCompleted(bool isSuccessful, string message, Transaction savedTransaction)
    {
        MessageBox.Show(message);

        if(isSuccessful)
        {
            // save new transaction to local database
            DatabaseBl.Save(savedTransaction);

            // save to observable collection Transactions in MainViewModel
            App.ViewModel.Transactions.Add(App.ViewModel.TransactionToTransactionViewModel(savedTransaction));
            App.ViewModel.SortTransactionList();

            // Go back to Transaction List
            NavigationService.GoBack();
        }
        else
        {
            // if REST is failed save unsent transaction to Phone database
            SaveTransactionToPhone(_currentTransaction);

            // save to observable collection Transactions in MainViewModel
            App.ViewModel.Transactions.Add(App.ViewModel.TransactionToTransactionViewModel(_currentTransaction));
            App.ViewModel.SortTransactionList();
        }

    }

Каждый объект транзакции имеет свойство IsInSync. По умолчанию он имеет значение false до тех пор, пока мы не получим подтверждение от REST API, что оно успешно сохранено на сервере.

Пользователь имеет возможность обновлять транзакции. Пользователь может нажать кнопку Обновить, чтобы получить новые данные с сервера. Мы выполняем синхронизацию в фоновом режиме следующим образом:

   private void RefreshTransactions(object sender, RoutedEventArgs e)
    {
        if (NetworkDetector.IsOnline)
        {
            var notSyncTransactions = DatabaseBl.GetData<Transaction>().Where(x => x.IsInSync == false).ToList();


            if(notSyncTransactions.Count > 0)
            {
                // we must Sync all transactions
                _isAllInSync = true;
                _transactionSyncCount = notSyncTransactions.Count;
                _transactionBl.AddTransactionCompleted += OnSyncTransactionCompleted;

                if (_progress == null)
                {
                    _progress = new ProgressIndicator();
                }

                foreach (var notSyncTransaction in notSyncTransactions)
                {
                    _transactionBl.AddTransaction(notSyncTransaction);
                }

                _progress.Show();
            }
            else
            {
                // just refresh transactions
                DoTransactionRefresh();
            }
        }
        else
        {
            MessageBox.Show(ApplicationStrings.NETWORK_OFFLINE);
        }
    }

 private void DoTransactionRefresh()
    {
        if (_progress == null)
        {
            _progress = new ProgressIndicator();
        }

        // after all data is sent do full reload
        App.ViewModel.LoadMore = true;
        App.ViewModel.ShowButton = false;
        ApplicationBl<Transaction>.GetDataLoadingCompleted += OnTransactionsRefreshCompleted;
        ApplicationBl<Transaction>.GetData(0, 10);

        _progress.Show();
    }

OnTransactionRefreshCompleted мы удаляем все данные транзакций в локальной базе данных и получаем последние 10 транзакций. Нам не нужны все данные, и таким образом пользователь синхронизировал данные. Он всегда может загрузить больше данных, нажав «загрузить больше» в конце списка транзакций. Это что-то похожее на эти твиттер-приложения.

 private void OnTransactionsRefreshCompleted(object entities)
    {
        if (entities is IList<Transaction>)
        {
            // save transactions
            var transactions = (IList<Transaction>)entities;
            DatabaseBl.TruncateTable<Transaction>();
            DatabaseBl.Save(transactions);
            ((MainViewModel) DataContext).Transactions.Clear();
            //reset offset
            _offset = 1;
            //update list with new transactions
            App.ViewModel.LoadDataForTransactions(transactions);

            App.ViewModel.LoadMore = false;
            App.ViewModel.ShowButton = true;
        }
        if (entities == null)
        {
            App.ViewModel.ShowButton = false;
            App.ViewModel.LoadMore = false;
        }

        // hide progress 
        _progress.Hide();

        // remove event handler
        ApplicationBl<Transaction>.GetDataLoadingCompleted -= OnTransactionsRefreshCompleted;
    }
1 голос
/ 02 апреля 2011

Предостережение - я не пробовал это с разработкой Windows Phone , но использование идентификаторов GUID - это то, что я обычно делаю, когда сталкиваюсь с подобными ситуациями - например, создание записей, когда у меня есть только одностороннее соединение сбаза данных - например, через шину сообщений или очередь.

Он отлично работает, хотя и с небольшим штрафом в размере записи, а также может привести к снижению производительности индексов.Я предлагаю вам просто попробовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...