对来自dapper result的每个记录调用一个函数

本文关键字:调用 函数 一个 记录 dapper result | 更新日期: 2023-09-27 17:54:57

我试图在每个记录上调用一个函数,将设置一些字段值。当要对结果进行分页时,可以通过以下方式实现:

public IDataWrapper GetPagedQuery<T>(string myQuery, object param, Action<T> customAction)
{
    var obj = new DataWrapper ();
    using (var oConn = CreateConnection(ConnectionString))
    {
        TotalPages totalRows = null;
        var list = oConn.Query<T, TotalPages, T>(myQuery, (e, t) =>
        {
            totalRows = t;
            if (mapAction != null) customAction(e);
            return e;
        }, param, splitOn: "SplitOn");
        obj.RowsFound = (IEnumerable<dynamic>)list;
        obj.TotalRows = totalRows == null ? 0 : totalRows.TotalRows;
    }
    return obj;
}

当结果不打算被分页时,我的问题来了。我在第一个例子中的查询包括对列的分割,这就是为什么它都有效,但是我的下一个查询是一个简单的查询,例如Select Column1, Column2 FROM MyAwesomeTable,它将返回所有行,列等…

问题是我仍然需要对返回的每个结果应用customAction。现在让我们想象一下,有几百万条记录返回的可能性(相信我,考虑到我的情况,这不是不现实的),因此我不想在每条记录之后再次循环并应用我的方法,我希望在dapper返回结果时应用该方法,就像在第一种情况下一样。

这是我尝试的:

public IDataWrapper GetNonPagedQuery<T>(string myQuery, object param, Action<T> customAction)
{
    var obj = new DataWrapper ();
    using (var oConn = CreateConnection(ConnectionString))
    {
        var list = oConn.Query<T>(myQuery, (e) =>
        {
            if (mapAction != null) customAction(e);
            return e;
        }, param).ToList();
        obj.RowsFound = (IEnumerable<dynamic>)list;
        obj.TotalRows = list.Count();
    }
    return obj;
}

我得到一个错误,上面的代码,它不能解决方法Query<T>(etc...我理解这是因为它不存在。我在这里问的是,完成我正在努力做的事情的最好方法是什么?

对来自dapper result的每个记录调用一个函数

我恐怕简短的回答是你不能这样做。

稍微长一点的答案是,在您的分页查询中,它本质上是通过数据的第二次传递,因为Dapper做一些工作将每一行的数据转换为"T"的实例,然后它对"map"方法进行单独调用,您使用该方法调用"customAction"。

因此,这与执行简单的非分页"conn.Query"调用以及随后执行customAction的传递之间的区别很小。如下所示:

public IDataWrapper GetNonPagedQuery<T>(string myQuery, object param, Action<T> customAction)
{
    var obj = new DataWrapper();
    using (var oConn = CreateConnection(ConnectionString))
    {
        var results = oConn
            .Query<T>(myQuery)
            .ToList();
        obj.TotalRows = results.Count();
        obj.RowsFound = results
            .Select(value =>
            {
                customAction(value);
                return value;
            })
            .Cast<dynamic>();
    }
    return obj;
}

如果你担心的是,你可能会加载许多,许多记录在非分页查询那么值得记住的是,所有的这些记录将被加载到内存一次;它们不会像对返回结果的枚举那样一次一个地从数据库中取出,这可能会对资源造成相当大的消耗(如果您讨论的数据太多,希望避免进行第二次枚举)。

必须是这种情况,因为SQL连接在GetNonPagedQuery返回时关闭,因此没有办法让调用者"按需"读取数据。如果您确实要处理大量数据,也许非分页查询不是最好的方法?

注意,在上面的代码中,"customAction"只会在枚举行时被调用,在GetNonPagedQuery返回之前不会触发所有的行。如果"customAction"可能是一个昂贵的操作,那么这可能对您有益。另一方面,如果您希望在GetNonPagedQuery返回之前为每个结果调用"customAction",那么您将需要在Cast()之后再调用一次ToList(),这取决于哪种场景对您更有用。

我不是分页查询或非分页查询方面的专家,但是如果有人希望对每一行应用操作,我已经根据gbjbaanb对Dapper文档的引用提出了这个问题。

public static async IAsyncEnumerable<T> QueryLazyWithActionAsync<T>(this DbConnection self, string sql, object query, Action<T> action)
{
    using var reader = await self.ExecuteReaderAsync(sql, query);
    var parser = reader.GetRowParser<T>();
    while (await reader.ReadAsync())
    {
        var row = parser(reader);
        action(row);
        yield return row;
    }
}

我这样用

var result = dmsConnection.QueryLazyWithActionAsync<CustomerResult>(sql, query, row =>
{
    Console.WriteLine($"Querying for customer {row.FullName}");
});

是的,可能是:

请参阅Dapper文档中关于每行类型切换的部分。我怀疑(即没有尝试过它自己),它不会工作,如果你使用相同的系统按摩的结果,通过读取每一行,并显式处理它的格式。