根据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。我错过了什么?
答案 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();