![](/img/trans.png)
[英]Why can't I return a Task<IEnumerable<out T>> without making my method async and using await
[英]Why is my IEnumerable<T>.Where iterator not executing inside a using block while Async call?
我確定這不是Dapper的問題,但是在以下代碼段中,我發現永遠不會執行提供給Where
函數的謂詞。
private async Task<IEnumerable<Product>> GetProducts()
{
using (var connection = await _connectionFactory.Create())
{
var products = await connection.QueryAsync<Product>("select * from Products");
return products.Where(p => p.Active);
}
}
但是,如果我移動操作到外using
它執行。
private async Task<IEnumerable<Product>> GetProducts()
{
var products = Enumerable.Empty<Product>();
using (var connection = await _connectionFactory.Create())
{
products = await connection.QueryAsync<Product>("select * from Products");
}
return products.Where(p => p.Active);
}
是否存在某種延遲執行?
在第一個示例中,如果可以在return語句中進行以下修改:
return products.Where(p => p.Active).ToList();
, 那么它將按預期工作 。
這里的問題是,推遲執行IEnumerable<Product>
上的Where
子句,該子句以Task<IEnumerable<Product>>
包裝在Task
中,但是現在您需要運行Task
,該Task
也將執行謂詞,不確定您如何執行Task或以這種方式包裝延遲的執行是否存在問題,但是最終結果是謂詞未按預期生效,即使將其應用於Dapper結果(默認情況下已緩沖) (無流)
在第二種情況下它可以工作,因為您完全擺脫了延遲執行,所以Enumerable.Empty<Product>()
可確保首先分配內存,因此在應用謂詞后立即執行謂詞,因此不會延遲執行。 實際上,謂詞是在using
塊外應用的任何方式
在Async方法中,您正在using
塊來處理連接,這主要是因為Dapper在內部分配了內存,這就是為什么所有數據都將通過該內存發送,然后disposed
連接並且斷言從不執行的原因。 我有類似的示例,它不依賴於數據庫連接,並且可以按預期工作,因此我們可以推斷出連接處置在謂詞不執行中起了作用。 在第二種情況下,謂詞是在using
block的外部應用的,因此連接配置沒有任何作用,並且已經分配了內存。
async Task Main()
{
var result = await GetTest();
result.Dump();
}
public async Task<IEnumerable<Test>> GetTest()
{
var value = await GetTestDb();
return value.Where(x => x.Id == 1);
}
public async Task<IEnumerable<Test>> GetTestDb()
{
return await Task.FromResult(
new List<Test>
{
new Test{Id = 1, Name = "M"},
new Test{Id = 2, Name = "S"}
}
);
}
public class Test
{
public int Id { get; set; }
public string Name { get; set; }
}
您的謂詞實際上並不作為謂詞。 它只是一個LINQ調用。
return products.Where(p => p.Active);
當執行上述行時,根據上一行中的查詢和QueryAsync
調用,表中的所有行已經填充了products
。
Dapper的優點在於,它可以為您提供對查詢編寫的完全控制。 因此,如果要過濾記錄,為什么不以這種方式編寫查詢呢?
using(var connection = ....)
{
var param = new DynamicParameters();
param.Add("@Active", 1);
var products = await connection.QueryAsync<Product>("select * from Products where Active = @Active", param);
return products;
}
然后,您應該刪除products.Where
。
關於您所提出的實際問題:
我無法重現該問題。 當我運行以下代碼以讀取控制台應用程序中的輸出時,它將返回預期的結果。
DbDataReader dbDataReader = new DbDataReader();
IEnumerable<Product> activeProducts = dbDataReader.GetProducts().Result;
Console.WriteLine(activeProducts.Count());
您的方法幾乎沒有修改,如下所示:
public class DbDataReader
{
string connectionString = @"....";
public async Task<IEnumerable<Product>> GetProducts()
{
using(var connection = await GetOpenConnection())
{
var products = await connection.QueryAsync<Product>("select * from Products;WAITFOR DELAY '00:00:05'");
return products.Where(p => p.Active);
}
}
private async Task<SqlConnection> GetOpenConnection()
{
SqlConnection sqlConnection = new SqlConnection(connectionString);
await sqlConnection.OpenAsync();
return sqlConnection;
}
}
請注意,我有意使用WAITFOR
延遲了QueryAsync
調用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.