Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Asynchronous methods not available for ObjectResult<T>

According to the documentation for EF6, ObjectResult implements IDbAsyncEnumerable<T>, IDbAsyncEnumerable - which should mean it implements asynchronous methods such as ObjectResult<T>.ToListAsync(), right?

However, I'm not seeing that as a possible method in Visual Studio when calling a stored procedure like this:

public async Task<List<MyObject>> GetResultFromMyStoredProcedure(string foo, string bar)
{
    return await context.My_Stored_Procedure(foo, bar).ToListAsync();
}

But calling the stored procedure as a query does seem to work:

public async Task<List<MyObject>> GetResultFromMyStoredProcedure(string foo, string bar)
{
    var fooParam = new SqlParameter("@foo", foo);
    var barParam = new SqlParameter("@bar", bar);
    return await context.Database.SqlQuery<T>("My_Stored_Procedure @foo, @bar", fooParam, barParam).ToListAsync();
}

I've made sure my project is referencing the correct EF dll (6.1.3) - using NuGet. What am I missing?

like image 293
DarkSkyForever Avatar asked Dec 11 '15 16:12

DarkSkyForever


People also ask

What happens if we execute an asynchronous method but don't await it?

The call to the async method starts an asynchronous task. However, because no Await operator is applied, the program continues without waiting for the task to complete. In most cases, that behavior isn't expected.

How do you get asynchronous in C#?

The async keyword turns a method into an async method, which allows you to use the await keyword in its body. When the await keyword is applied, it suspends the calling method and yields control back to its caller until the awaited task is complete. await can only be used inside an async method.

How do you make something async?

You can use await Task. Yield(); in an asynchronous method to force the method to complete asynchronously. Insert it at beginning of your method and it will then return immediately to the caller and complete the rest of the method on another thread.


1 Answers

Update

Since you can't just convert to Queryable, I've decompiled the internal methods that EF uses for IDbAsyncEnumerable and made this extension method (out of the microsoft decompiled sources, so it should be as good as it gets):

public static Task<List<T>> ToListAsync<T>(this IDbAsyncEnumerable<T> source, CancellationToken cancellationToken)
{
    TaskCompletionSource<List<T>> tcs = new TaskCompletionSource<List<T>>();
    List<T> list = new List<T>();
    ForEachAsync<T>(source.GetAsyncEnumerator(), new Action<T>(list.Add), cancellationToken).ContinueWith((Action<Task>)(t =>
    {
        if (t.IsFaulted)
            tcs.TrySetException((IEnumerable<Exception>)t.Exception.InnerExceptions);
        else if (t.IsCanceled)
            tcs.TrySetCanceled();
        else
            tcs.TrySetResult(list);
    }), TaskContinuationOptions.ExecuteSynchronously);
    return tcs.Task;
}

private static async Task ForEachAsync<T>(IDbAsyncEnumerator<T> enumerator, Action<T> action, CancellationToken cancellationToken)
{
    using (enumerator)
    {
        cancellationToken.ThrowIfCancellationRequested();
        if (await System.Data.Entity.Utilities.TaskExtensions.WithCurrentCulture<bool>(enumerator.MoveNextAsync(cancellationToken)))
        {
            Task<bool> moveNextTask;
            do
            {
                cancellationToken.ThrowIfCancellationRequested();
                T current = enumerator.Current;
                moveNextTask = enumerator.MoveNextAsync(cancellationToken);
                action(current);
            }
            while (await System.Data.Entity.Utilities.TaskExtensions.WithCurrentCulture<bool>(moveNextTask));
        }
    }
}

And you can have an overload without CancellationToken like:

public static Task<List<T>> ToListAsync<T>(this IDbAsyncEnumerable<T> source)
{
   return ToListAsync<T>(source, CancellationToken.None);
}

Old answer (not working)

Not sure if I'm getting the right grip of the question, but can't you simply do this?

return await context.My_Stored_Procedure(foo, bar).AsQueryable().ToListAsync();
like image 130
Jcl Avatar answered Oct 31 '22 04:10

Jcl