Asynchronous methods not available for ObjectResult

c# entity-framework-6

Question

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?

1
6
12/11/2015 4:47:42 PM

Accepted Answer

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();
14
12/11/2015 6:35:46 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow