ObjectResult <t>不可用的异步方法

时间:2015-12-11 16:05:06

标签: c# entity-framework-6

根据EF6的documentation,ObjectResult实现了IDbAsyncEnumerable <T>,IDbAsyncEnumerable - 这意味着它实现了异步方法,如ObjectResult <T> ToListAsync(),对吧?

但是,在调用这样的存储过程时,我没有在Visual Studio中看到这是一种可能的方法:

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

但是将存储过程作为查询调用似乎确实有效:

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();
}

我确保我的项目引用了正确的EF dll(6.1.3) - 使用NuGet。我错过了什么?

1 个答案:

答案 0 :(得分:12)

更新

由于您无法转换为可查询,因此我反编译了EF用于IDbAsyncEnumerable的内部方法并制作了此扩展方法(来自微软反编译源,因此它应该是尽可能好):

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));
        }
    }
}

你可以在没有CancellationToken的情况下过载:

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

旧答案(无法正常工作

不确定我是否能正确掌握问题,但你不能这样做吗?

return await context.My_Stored_Procedure(foo, bar).AsQueryable().ToListAsync();