从dapper结果中调用每条记录上的函数

时间:2016-07-05 19:37:57

标签: c# asp.net-mvc-5 dapper

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

StructuredQueryBuilder sb = ...
StructuredQueryDefinition sq =
  sb.and(
    sb.document("uriB"), 
    sb.containerQuery(sb.jsonProperty("timestamp"), myTimestamp));

当问题的结果不是要分页时,我的问题就来了。我在第一个示例中的查询包括拆分列,这就是为什么它一切正常,但我的下一个查询是一个简单的查询,例如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; } 将返回所有行,列等......

问题是我仍然需要对返回的每个结果应用customAction。现在让我们想象一下,有可能有几百万条记录回来(相信我,根据我的情况,这不是不切实际的),因此我不想再次循环遍历每条记录并应用我的方法,我想要那种方法应用作为精巧的人正在返回结果,就像在第一种情况下一样。

以下是我的尝试:

Select Column1, Column2 FROM MyAwesomeTable

我收到上述代码的错误,因为它无法解决方法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; } 我理解这是因为它不存在。我在这里问什么是完成我想要做的最好的方法?是否有可能与小巧玲珑。

3 个答案:

答案 0 :(得分:1)

我担心简短的回答是你不能这样做。

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

因此,在执行简单的非分页“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&lt; dynamic&gt;()之后你需要再多一个ToList()调用,它只取决于哪个场景对你更有用。

答案 1 :(得分:1)

我不是分页查询或非分页查询的专家,但是如果有人想对每行应用操作,我会根据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}");
});

答案 2 :(得分:0)

是的,可能是:

请参阅有关Type Switching per Row的Dapper文档部分。我怀疑(即我自己没试过),如果你使用相同的系统通过读取每一行并明确地处理它来将结果按到你想要的格式,它将无法工作。