从EF核心查询返回Task <ireadonlycollection <t >>而不等待?

时间:2018-07-09 12:53:02

标签: c# entity-framework-core ef-core-2.1

我希望我的类型尽可能具体。提供封装查询的方法时,通常会看到返回List<T>(或更具体地说是Task<List<T>>。)EF Core的.ToListAsync()方法也就不足为奇了。但这不是很准确吗? List<T>是SQL Server(或您使用的任何持久性)中较大集合的投影。这是不可修改的。

我想从我的方法中返回IReadOnlyCollection<T>。这似乎更准确。我正在从源数据返回一个投影,您不能通过修改投影来修改源数据。在不回退到List<T>的情况下,也不能错误地修改我的结果,这时您已经走了很远,我假设您知道自己在做什么。

所以我试图像同步地那样只返回接口。

public Task<IReadOnlyCollection<TResult>> GetResultAsync() =>
  _dbContext.Where(x => x.Property == true).ToListAsync();

我在这里避免使用asyncawait运算符。我想立即传递任务,以避免await的开销。但是,当包装在Task<T>中时,C#的类型系统无法识别包装的List<T>可转换为IReadOnlyCollection<T>。因此无法将Task<List<T>>强制转换为Task<IReadOnlyCollection<T>>。当然,您可以尝试进行显式强制转换,但是出于相同的原因,编译器也不愿意这样做。

那很烦人。但是我们可以很容易地用Task<T>剥离async wait

public async Task<IReadOnlyCollection<TResult>> GetResultAsync() =>
  await _dbContext.Where(x => x.Property = true).ToListAsync();

为了避免添加代码,我考虑了扩展方法。

public static async Task<IReadOnlyCollection<T>> ToReadOnlyCollectionAsync<T>(this IQueryable<T> query) =>
  await query.ToListAsync();

这使await脱离了我的方法,但是当然仍然要增加另一个等待时间。是否有一种方法可以从EF Core 2.1中免费退还Task<IReadOnlyCollection<T>>

1 个答案:

答案 0 :(得分:1)

不知道ToListAsync()会做什么,只是按名称进行,如果我猜对了,它将迭代结果并将其转换为后台线程上的列表,并返回必须为{{1 }}生成列表之前。

如果是这样,您的问题是

  

如何将awaited转换为Task<List<T>>

如果是这样,理论上您可以执行以下操作:

Task<IReadonlyCollection<T>>

我不相信 public Task<IReadOnlyCollection<string>> ToReadOnlyCollection() { return ToListAsync().ContinueWith(x => new ReadOnlyCollection<string>(x.Result) as IReadOnlyCollection<string>); } public Task<IReadOnlyList<string>> ToReadOnlyList() { // if you don't mind an IReadOnlyList, you can use this // one which doesn't involve creating a new collection return ToListAsync().ContinueWith(x => x.Result as IReadOnlyList<string>); } private Task<List<string>> ToListAsync() { return Task.Run(() => { Task.Delay(1000); return new List<string> { "1", "2", "3" }; }); } 允许使用反方差,因此Task<T>(其中,Child:Parent)不能自动转换为Task<TChild>,因此您需要自己进行操作。