Невозможно получить доступ к данным SQLite в MvvmCross ViewModel - PullRequest
0 голосов
/ 24 января 2019

Привет сообщество StackOverflow,

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

Недавно для проекта, над которым я работаю, мы решили обновить MvvmCross 5.7.0 до 6.2.2. Мне удалось заставить наше приложение UWP успешно завершить процесс инициализации и настройки. Первая модель представления, для которой мы регистрируем запуск приложения, также начинает инициализацию. Тем не менее, я обнаружил, что моя инициализация vm зависает в определенной строке кода (показано в коде ниже). Самое странное, что аналогичные методы, вызываемые в коде инициализации приложения, работают отлично, без зависания / тупика, поэтому я не уверен, в чем дело. Вот упрощенная версия моего кода модели представления для иллюстрации:

public class MyViewModel : BaseAuthenticatedTabBarViewModel, IMvxViewModel<int>
{
    private int? _settingValue;

    public override async Task Initialize()
    {
        //Some irrelevant initialization code
        Exception e = null;
        try
        {
             //This line of code never returns
            _settingValue = _settingValue ?? await AppSettingService.GetSettingValue();
        }
        catch (Exception ex)
        {
            e = ex;
        }

        if (e != null)
        {
            await HandleCatastrophicError(e);
        }
    }
}

Метод AppSettingService.GetSettingValue () выглядит следующим образом:

public async Task<int?> GetCurrentEventId()
{
    return await GetNullableIntSetting("SettingValue");
}

private static async Task<int?> GetNullableIntSetting(string key)
{
    try
    {
        var setting = await SettingDataService.SettingByName(key);
        if (setting != null)
        {
            return string.IsNullOrEmpty(setting.Value) ? (int?)null : Convert.ToInt32(setting.Value);
        }
    }
    catch (Exception ex)
    {
        //Handle the exception
    }
    return null;
}

Весь код для SettingDataService:

public class SettingDataService : DataService<SettingDataModel>, ISettingDataService
{
    public async Task<SettingDataModel> SettingByName(string name)
    {
        try
        {
            var values = (await WhereAsync(e => e.Name == name));
            return values.FirstOrDefault();
        }
        catch(Exception ex)
        {
            //Handle the exception
        }
        return null;
    }
}

Наконец, реализация WhereAsync () находится в классе DataService и выглядит следующим образом:

public virtual async Task<IEnumerable<T>> WhereAsync(System.Linq.Expressions.Expression<Func<T, bool>> condition, SQLiteAsyncConnection connection = null)
    {
        return await (connection ?? await GetConnectionAsync())
            .Table<T>()
            .Where(condition)
            .ToListAsync();
    }

Большое спасибо за вашу помощь заранее

Редактировать: Забыл также добавить этот важный фрагмент кода, чтобы помочь вам, ребята, еще дальше:

protected async Task<SQLiteAsyncConnection> GetConnectionAsync()
{
    SQLiteAsyncConnection connection = null;
    while (true)
    {
        try
        {
            connection = Factory.Create(App.DatabaseName);
            // This line of code is the culprit. For some reason this hangs and I can't figure out why.
            await connection.CreateTableAsync<T>();
            break;
        }
        catch (SQLiteException ex)
        {
            if (ex.Result != Result.CannotOpen && ex.Result != Result.Busy && ex.Result != Result.Locked)
            {
                throw;
            }
        }

        await Task.Delay(20);

    }
    return connection;
}

1 Ответ

0 голосов
/ 24 января 2019

Я подозреваю, что вы звоните Task.Wait или Task<T>.Result куда-нибудь выше вашего стека вызовов. Или, если вы этого не делаете, MvvmCross , вероятно, делает это для вас . Это вызывает тупик при вызове из контекста пользовательского интерфейса.

Лично я предпочитаю подход, согласно которому ViewModels всегда должны создаваться синхронно и не может иметь асинхронную "инициализацию". То есть они должны сами (синхронно) перевести себя в состояние «загрузки», и эта конструкция может запустить асинхронную операцию, которая позже обновит их * до состояния «загрузки». Шаблон синхронной инициализации означает, что при смене представлений никогда не бывает ненужной задержки; Ваши пользователи могут видеть только спиннер или загрузочное сообщение, но, по крайней мере, они увидят что-то . См. Мою статью о асинхронной привязке данных MVVM , в которой описан шаблон, который помогает с этим, и обратите внимание, что в этой статье есть более новая версия вспомогательных типов .

...