我确定这不是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);
}
是否存在某种延迟执行?
答案 0 :(得分:1)
在第一个示例中,如果可以在return语句中进行以下修改:
return products.Where(p => p.Active).ToList();
,然后它将按预期运行。
这里的问题是Where
上应用的IEnumerable<Product>
子句被推迟执行,它以Task
的形式包装在Task<IEnumerable<Product>>
中返回,但是现在您需要运行Task
(也将执行谓词),不确定您如何执行Task或以这种方式包装延迟执行会出现问题,但是最终结果是谓词未如预期那样生效,即使将其应用于Dapper结果,默认情况下也会缓冲(无流)
它在第二种情况下有效,因为您完全摆脱了延迟执行,Enumerable.Empty<Product>()
确保首先分配了内存,因此谓词在应用后立即执行,没有延迟执行。实际上,谓词是在using
块之外应用的任何方式
在Async方法中,您要使用using
块来处理连接,这主要是因为Dapper内部分配了内存,这就是为什么所有数据都通过其发送的原因,因此连接是disposed
,而谓词永远不会被执行。我有类似的示例,它不依赖于数据库连接,并且可以按预期工作,因此我们可以推断出连接处置在谓词不执行中起了作用。在第二种情况下,谓词在using
块外部应用,因此连接处理没有任何作用,并且已经分配了内存。
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; }
}
答案 1 :(得分:0)
您的谓词实际上并不充当谓词。这只是一个LINQ调用。
return products.Where(p => p.Active);
执行以上行时,根据您的查询,表中的所有行已经填充products
,并在上一行中调用QueryAsync
。
关于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;
}
}
请注意,我故意推迟了QueryAsync
的{{1}}通话。