异步方法不可用于ObjectResult<;T>;
本文关键字:lt gt ObjectResult 用于 异步方法 | 更新日期: 2023-09-27 18:26:23
根据EF6的文档,ObjectResult实现了IDbAsyncEnumerable <T>
、IDbAsync Enumerable,这意味着它实现了ObjectResult <T>
等异步方法ToListAsync(),对吗?
然而,在VisualStudio中,当调用这样的存储过程时,我并不认为这是一种可能的方法:
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。我错过了什么?
更新
由于你不能直接转换为Queryable,我已经反编译了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();