当前位置: 首页 > 知识库问答 >
问题:

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

乔凯康
2023-03-14

在winform应用程序中使用EntityFrmework 6.2异步方法时,我遇到了一个问题。我们使用自定义类来管理基于单个活动设置的同步或异步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将在异步模式下加载对象的两个子集合,而我们有错误:在前一个异步操作完成之前在此上下文中启动了第二个操作。使用“等待”确保在此上下文中调用另一个方法之前完成了任何异步操作。任何实例成员都不能保证是线程安全的。

共有1个答案

戎志勇
2023-03-14

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

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

另一方面,我强烈建议您将方法更改为异步。像这样跳过wait是一种“fire and forget”的方法,它有两个主要问题:

  1. 您的代码无法知道操作何时完成。现在我可以重新使用这个数据库上下文吗?它已经完成了db操作?知道所有数据库更新都已应用,我可以安全退出应用程序吗?这些问题无法用“开火并忘记”代码来回答
 类似资料:
  • 消息: 代码: 我尝试的: 我不知道我做错了什么,我尝试了不同的方法,比如: 1. 2. 3. 我做错了什么?

  • 在我的控制器中,我在保存到DB的日期之后执行另一个Void函数。但有时会出现这种错误: 在上一个异步操作完成之前,在此上下文上启动了第二个操作。使用“await”确保在该上下文上调用另一个方法之前已完成任何异步操作。任何实例成员都不能保证线程安全。 ...下面是我的控制器示例: 下面是Void方法: 我怎么解决这个问题?

  • 我是Selenium的新手。我正在尝试使用Selenium自动执行网页中表格的过滤(按type=New)和排序(按日期降序)步骤。我使用函数sendKeys()和Click()进行这些操作。 我在sendKeys和click函数之间使用了Thread.sleep(1000 ),以便在对列表进行排序之前按照类别对其进行过滤。 有没有办法让代码等到页面在sendKeys()之后被过滤,然后继续点击操作

  • 问题内容: 我有一个JavaScript函数,该函数使用jQuery发出两个连续的Ajax请求。我想确保在调用第二个函数之前已加载第一个请求。有办法吗? 问题答案: 在选项中指定,或在第一个调用的回调中进行第二个ajax 调用。

  • 我有一个带有Vaadin集成(v14)的Spring Boot项目。我希望我的应用程序做一些后台操作,并在基于Vaadin的前端上表示结果。为此,我有一个视图,它是用Vaadin Designer(.js)生成的聚合物模板,并连接到Java companion类。在这个视图中,我只是简单地添加了一个用以下监听器初始化的按钮: 我正试图访问文档中所说的UI。然而,当它被执行时,它只到达第一个“等待”

  • 我得到了关于在上一个异步操作结束之前在上下文上启动第二个异步操作的错误,但我没有看到它发生在哪里。这是我正在使用的代码。每个异步调用都使用await,那么我做错了什么? 这是Web API 2调用上的一种方法。 当它到达最后一行时,就是抛出异常的地方。 异常消息: 在上一个异步操作完成之前,在此上下文上启动了第二个操作。使用“await”确保在该上下文上调用另一个方法之前已完成任何异步操作。任何实