在上一个异步操作完成之前,在此上下文上启动了第二个操作。使用'await'确保



我正在努力解决使用 EntityFrmework 6.2 异步方法进入 winform 应用程序的问题。 我们使用自定义类来管理基于单个活动设置的同步或异步 EntityFrmework 访问。当我们使用同步访问时,一切正常。当我们使用异步调用时,我们会遇到这个问题:在上一个异步操作完成之前,在此上下文上启动了第二个操作。使用"await"确保在此上下文中调用另一个方法之前已完成任何异步操作。不保证任何实例成员都是线程安全的。 我们已经阅读了很多关于这个问题的帖子,但没有一个可以帮助我们解决问题。

我们知道问题与从同步调用异步方法有关,不幸的是我们无法将调用方法从同步转换为异步。 我们从项目中提取了两种方法来演示所描述的行为

public void AddLoadingRequest(Func<Task> fnAsync, Action fnSync, Action bsa)
{
try
{
Task task = Task.Run(async () => await DoDataSource(fnAsync, fnSync, bsa));
_lstTask.Add(task);
if (task.IsFaulted)
throw task.Exception;
}
catch (Exception ex)
{
MessageBox.Show($"Error {ex.Message}");
}
}
protected async Task DoDataSource(Func<Task> fnAsync, Action fnSync, Action bsa)
{
try
{
if (_bLoadingFKTableAsync == true)
await fnAsync();
else
fnSync();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Loading Error");
throw;
}
}

调用方法:

private void btnTest_Click(object sender, EventArgs e)
{
NWContext wContext = new NWContext();
Customers cust = wContext.Customers.FirstOrDefault(w => w.CustomerID == "RATTC");
BindingSource bsCustomer = new BindingSource();
BindingSource bsOrders = new BindingSource();
BindingSource bsCustomerDemographics = new BindingSource();
bsCustomer.DataSource = cust;
_bLoadingFKTableAsync = true;
AddLoadingRequest(
() => wContext.Entry(cust).Collection(typeof(Orders).Name).LoadAsync(),
() => wContext.Entry(cust).Collection(typeof(Orders).Name).Load(),
() =>
{
bsOrders.SuspendBinding();
bsOrders.DataSource = cust.Orders;
bsOrders.ResumeBinding();
});
AddLoadingRequest(
() => wContext.Entry(cust).Collection(typeof(CustomerDemographics).Name).LoadAsync(),
() => wContext.Entry(cust).Collection(typeof(CustomerDemographics).Name).Load(),
() =>
{
bsCustomerDemographics.SuspendBinding();
bsCustomerDemographics.DataSource = cust.CustomerDemographics;
bsCustomerDemographics.ResumeBinding();
});
}

我们期望 EntityFramework 将以异步模式加载对象的两个子集合,而我们遇到错误:在上一个异步操作完成之前,在此上下文上启动了第二个操作。使用"await"确保在此上下文中调用另一个方法之前已完成任何异步操作。不保证任何实例成员都是线程安全的。

问题是:我们如何从现有同步方法内部调用两个或多个异步 EF 请求?

您需要两个或更多数据库上下文。每个人一次只能有一个请求。

附带说明一下,我强烈建议您将方法更改为async。像这样跳过await是一种"即发即弃"的方式,它有两个主要问题:

  1. 代码无法知道操作何时完成。现在,我是否可以重用此数据库上下文,因为它已完成该数据库操作?在知道已应用所有数据库更新的情况下,我是否可以安全地退出应用程序?这些问题无法用"即发即弃"代码来回答。
  2. 代码无法知道操作是否成功。使用"即发即弃",您的代码必须假设它有效。

相关内容

最新更新