无法在MvvmCross ViewModel中访问SQLite数据

时间:2019-01-23 22:32:30

标签: sqlite xamarin uwp migration mvvmcross

Hello StackOverflow社区,

我知道这篇文章中有很多代码,但是我想给大家,社区尽可能多的关于这里发生的事情的图片,以便有人可以帮助我弄清楚我的问题是。

最近,对于我正在从事的项目,我们决定从MvvmCross 5.7.0升级到6.2.2。我已经设法使我们的UWP应用程序成功完成了初始化和设置过程。我们为其注册应用程序启动的第一个viewmodel也开始初始化。但是,我发现我的虚拟机初始化挂在特定的代码行上(如下面的代码所示)。最奇怪的部分是应用初始化代码中调用的类似方法,无需挂起/死锁即可完美运行,因此我不确定有什么不同。这是我的viewmodel代码的简化版本,用于说明:

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 :(得分:3)

我怀疑您正在呼叫堆栈中更远的某个地方呼叫Task.WaitTask<T>.Result。或者,如果您不这样做,则MvvmCross is可能是doing it for you。从UI上下文调用时,它将cause a deadlock

个人而言,我更喜欢ViewModels应该始终同步构造并且不能具有异步“初始化”的方法。也就是说,它们必须将自己(同步)构造为“正在加载”状态,并且这种构造可以启动异步操作,该异步操作随后会将它们更新为“已加载”状态。同步初始化模式意味着更改视图时永远不会有不必要的延迟。您的用户可能只会看到微调框或加载消息,但至少他们会看到某物。请参阅我在async MVVM data binding上的文章以获取有助于解决此问题的模式,并注意其中有一个newer version of the helper types in that article