从小巧的结果中调用每条记录的函数

Call a function on each record from dapper result

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

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 将 return 所有行、列等...

问题是我仍然需要对返回的每个结果应用 customAction。现在让我们想象一下,有可能返回几百万条记录(相信我,考虑到我的情况,这并非不切实际),因此我不想在事后再次遍历每条记录并应用我的方法,我想要那个方法作为短小精悍的应用程序是 returning 结果,就像第一种情况一样。

这是我尝试过的:

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可以吗

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

稍微长一点的答案是,在您的分页查询中,它本质上是第二次遍历数据,因为 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 returns 关闭,因此无法保持打开状态以读取数据 "on demand"呼叫者,召集者。如果您真的要处理大量数据,也许非分页查询不是最好的方法?

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

是的,可能是:

请参阅有关 Type Switching per Row 的 Dapper 文档部分。我怀疑(即我自己没有尝试过)如果您使用相同的系统通过读取每一行并显式处理它来将结果按您想要的格式进行处理,它就不会起作用。

我不是分页查询或 non-paged 查询方面的专家,但如果有人希望对每一行应用操作,我已经根据 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}");
});