How do I kick off an entity stored procedure in EF6 async and not wait for a return?
Asked Answered
C

2

16

I'd like to just punt a call over to the SQL Server and not wait for a return. I have an imported Entity Function from a Stored Procedure that I'd like to call asynchronously this way in Entity Framework 6.0.0-rc1. Is this possible? What's the syntax?

Entity Function: RecalculateBudgetNumbers(int id)
Cutin answered 8/10, 2013 at 14:32 Comment(1)
dont get stuck at the Entity-Framework! You can use those methods async like you can use everything else async. (Task.Run, Thread, async (since 4.5))Dietary
R
8

Start a new Task that creates a fresh data context and invokes that function. Just don't wait/await that task. Let it run by itself to completion.

Make sure to log errors. Don't swallow exceptions because they might be bugs you want to know about.

In an ASP.NET setting, be aware that the worker process can recycle at any time at all, so your background work can suddenly disappear (or be cancelled).

Rolland answered 8/10, 2013 at 14:45 Comment(2)
I added some code. When I try to remove await in RecalculateBudgetNumbersAsync, VS gives me a warning: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. How do I let it run itself out without waiting for a return?Cutin
@Rolland spent a lot of time trying to get my example to work using different trials. My async needs included saving using dbcontext. Your comment of using a fresh data context helped a lot. thxColumn
C
5

Ahh. I was in Entity Framework land too long. Thanks for the tips. Here's what worked for me. Do you see any problems with this?

    /// <summary>
    /// kicks off the LONG RUNNING calculations on a budget to regenerate all pre-cooked numbers.
    /// </summary>
    /// <param name="budgetId">Budget Id</param>
    public async System.Threading.Tasks.Task RecalculateBudgetNumbersAsync(int budgetId)
    {
        await System.Threading.Tasks.Task.Factory.StartNew(() => RecalculateBudgetNumbers(budgetId));
    }

    public static void RecalculateBudgetNumbers(int budgetId)
    {
        //this is static so we don't use the unit of work..
        using (BMTContext ctx = new BMTContext())
        {
            ctx.UpdateLifeOfBudgetNumbers(budgetId);                
            ctx.UpdateIntervalNumbers(budgetId);                
            ctx.UpdateIntervalActivityNumbers(budgetId);
            ctx.UpdateLifeOfBudgetActivityNumbers(budgetId);
        }
    }

And my test (I'm in Visual Studio 2012 so I can do an async test).

    [TestMethod]
    public async System.Threading.Tasks.Task RecalculateBudgetNumbersAsyncTest()
    {
        System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
        timer.Start();
        await repo.RecalculateBudgetNumbersAsync(budgetId);

        System.Console.WriteLine("RecalculateBudgetNumbersAsyncTest milliseconds: " + timer.ElapsedMilliseconds.ToString());
    }

After suggestions from Matt Smith and Usr, I changed RecalculateBudgetNumbersAsync to this. I hope this is what they meant:

    public void RecalculateBudgetNumbersAsync(int budgetId)
    {
        System.Threading.Tasks.Task.Factory.StartNew(() => RecalculateBudgetNumbers(budgetId));
    }
Cutin answered 8/10, 2013 at 14:58 Comment(2)
No need for the async/await keywords in RecalculateBudgetNumbersAsync. Remove them and you'll have equivalent functionality.Billow
One question - Will releasing the primary thread and starting a new one not decrease the performance!? There seems to be an overhead of spawning the new thread and then later resuming on the primary, when the new one completes. Is it?Ron

© 2022 - 2024 — McMap. All rights reserved.