簡體   English   中英

為什么我的IEnumerable <T> 。在異步調用時,迭代器未在using塊內執行?

[英]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(); 那么它將按預期工作

情況1:

這里的問題是,推遲執行IEnumerable<Product>上的Where子句,該子句以Task<IEnumerable<Product>>包裝在Task中,但是現在您需要運行Task ,該Task也將執行謂詞,不確定您如何執行Task或以這種方式包裝延遲的執行是否存在問題,但是最終結果是謂詞未按預期生效,即使將其應用於Dapper結果(默認情況下已緩沖) (無流)

情況2:

在第二種情況下它可以工作,因為您完全擺脫了延遲執行,所以Enumerable.Empty<Product>()可確保首先分配內存,因此在應用謂詞后立即執行謂詞,因此不會延遲執行。 實際上,謂詞是在using塊外應用的任何方式


在Async方法中,您正在using塊來處理連接,這主要是因為Dapper在內部分配了內存,這就是為什么所有數據都將通過該內存發送,然后disposed連接並且斷言從不執行的原因。 我有類似的示例,它不依賴於數據庫連接,並且可以按預期工作,因此我們可以推斷出連接處置在謂詞不執行中起了作用。 在第二種情況下,謂詞是在using block的外部應用的,因此連接配置沒有任何作用,並且已經分配了內存。


示例代碼(使用LinqPad):

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM