异步读取数据库数据的正确方法是什么

本文关键字:方法 是什么 读取 数据库 数据 异步 | 更新日期: 2023-09-27 18:00:12

你能告诉我一个错误吗?为什么我让以下代码同步运行,并在向DB发出异步请求时阻止UI?提前谢谢。

我的视图模型:

public virtual bool MerchantsLoading { get; set; }
public virtual ObservableCollectionCore<Merchant> Merchants { get; set; }
public MerchantViewModel { //constructor
    MerchantsLoading = true;
    Merchants = SQLite.GetMerchants().Result;
    SQLite.GetMerchants().ContinueWith(task => MerchantsLoading =     false);
}

我的观点:

...
<dxg:GridControl ShowLoadingPanel="{Binding MerchantsLoading}" ItemsSource="{Binding Merchants}".../>
...

SQLite.GetMerchants():

public static async Task<ObservableCollectionCore<Merchant>> GetMerchants()
{
    SQLiteConnection SqlConnection = new SQLiteConnection(MerchantDB);
    var Merchants = new ObservableCollectionCore<Merchant.Merchant>();
    try
    {
        await SqlConnection.OpenAsync();
        SQLiteCommand myCommand = new SQLiteCommand("select * from merchant", SqlConnection);
        DbDataReader myReader = await myCommand.ExecuteReaderAsync();
        while (myReader.Read())
        {
            Merchants.Add(new Merchant.Merchant
            {
                ID = Convert.ToInt32(myReader["ID"]),
                Name = Convert.ToString(myReader["Name"])
            });
        }
    }
    catch (Exception ex)
    {
        Messenger.Default.Send(new LogMessage { Message = "Ошибка в процедуре GetMerchants" });
        Messenger.Default.Send(new LogMessage { Message = ex.ToString() });
    }
    finally
    {
        SqlConnection.Close();
    }
    return Merchants;
}

我添加了在UserControl.Loaded事件上激发的新函数,但UI仍然被阻止(视图模型构造函数现在为空):

public async void Loaded()
{
    MerchantsLoading = true;
    Merchants = await SQLite.GetMerchants();
    await SQLite.GetMerchants().ContinueWith(task => MerchantsLoading = false);
}

DevExpress MVVM Framework的EventToCommand触发的已加载事件:

<UserControl xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core" 
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm" xmlns:ViewModels="clr-namespace:ORBKWorker.Merchant"
         xmlns:Helpers="clr-namespace:ORBKWorker.Helpers"
         xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"
         xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
         xmlns:dxlc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol"
         x:Class="ORBKWorker.Merchant.MerchantView"
         mc:Ignorable="d"
         DataContext="{dxmvvm:ViewModelSource Type={x:Type ViewModels:MerchantViewModel}}"
         d:DesignHeight="800" d:DesignWidth="1920">
<UserControl.Resources>
    <Helpers:IntToEmailType x:Key="IntToEmailType"/>
</UserControl.Resources>
<dxmvvm:Interaction.Behaviors>
    <dxmvvm:EventToCommand EventName="Loaded" Command="{Binding LoadedCommand}"/>
</dxmvvm:Interaction.Behaviors>
<Grid>...

最后决定使用BackgroundWorker:

    public void GetMerchants()
    {
        MerchantsLoading = true;
        BackgroundWorker bgw = new BackgroundWorker();
        bgw.DoWork += (sender, args) => Merchants = SQLite.GetMerchants();
        bgw.RunWorkerCompleted += (sender, args) => MerchantsLoading = false;
        bgw.RunWorkerAsync();
    }

异步读取数据库数据的正确方法是什么

您通过在Task上调用Result来阻塞线程:

Merchants = SQLite.GetMerchants().Result;

相反,您应该等待Task。不幸的是,您无法生成构造函数async,因此您必须将代码移动到事件处理程序,可能是Loaded或其他什么程序,然后生成async

正如您所发现的,SQLite异步方法实际上并不是异步的。因此,您需要使用像Task.Run这样的后台线程。

可以Loaded事件中执行此操作:

public async void Loaded()
{
  MerchantsLoading = true;
  Merchants = await Task.Run(() => SQLite.GetMerchants());
  MerchantsLoading = false;
}

然而,我认为使用我的NotifyTask<T>类型:会更干净

public virtual NotifyTask<ObservableCollectionCore<Merchant>> Merchants { get; set; }
public MerchantViewModel()
{
  Merchants = NotifyTask.Create(Task.Run(() => SQLite.GetMerchants()));
}

带视图:

<dxg:GridControl ShowLoadingPanel="{Binding Merchants.IsNotCompleted}" ItemsSource="{Binding Merchants.Result}" .../>