Dapper icon indicating copy to clipboard operation
Dapper copied to clipboard

Using Multi-Mapping type[] parameter with QueryUnbufferedAsync

Open chipmunkofdoom2 opened this issue 2 years ago • 5 comments

Does an overload exist to use the type[] parameter for the QueryUnbufferedAsync overload? My goal is to have QueryUnbufferedAsync work similarly to QueryAsync when specifying a collection of types. Something like this:

var query = "SELECT * FROM Customers C JOIN Addresses A ON C.ID = A.CustomerID";
using var connection = connectionFactory.GetConnection();

//Currently possible
var customers = await connection.QueryAsync<Customer>(query, new Type[] { typeof(Customer), typeof(Address) }, (row) =>
{
    var customer = (Customer)row[0];
    customer.Address = (Address)row[1];
    return customer;
});
return customers;

//Would like to do this:
await foreach(var customer in connection.QueryUnbufferedAsync<Customer>(query, new Type[] { typeof(Customer), typeof(Address) }, (row) =>
{
    var customer = (Customer)row[0];
    customer.Address = (Address)row[1];
    return customer;
}))
{
    yield return customer;
}

chipmunkofdoom2 avatar Oct 12 '23 10:10 chipmunkofdoom2

That API is missing on the unbuffered async path right now, but that was more a timing thing; we should be able to go back and add the missing ones. In this case, this is presumably better using QueryUnbufferedAsync<Customer, User, Customer>(...) (which also doesn't exist, note)

mgravell avatar Oct 12 '23 12:10 mgravell

Thanks, appreciate the response. In this case, the overload with generic parameters could be simpler. However, I've gotten in the habit of using the overload that accepts Type[] since some of my database objects have more relations than generic type parameters. It's simpler for me to use the Type[] overload everywhere, even when there's only one or two relations.

I did some digging around in the codebase, it looks like an async implementation of MultiMapImpl would get us most of the way there. Instead of using the synchronous Read and Next methods on the DbDataReader, we'd us the async methods similar to how QueryUnbufferedAsync works. Something like this:

while (await reader.ReadAsync(cancel).ConfigureAwait(false))
{
    yield return mapIt(reader);
}
if (finalize)
{
    while (await reader.NextResultAsync(cancel).ConfigureAwait(false)) { /* ignore subsequent result sets */ }
    command.OnCompleted();
} 

It feels a bit wasteful just to copy and paste MultiMapImpl just to change the Read/NextResult calls. We'd also need a overload of QueryUnbufferedAsync to accept the Type[] parameter and call the new MultiMapImplAsync.

chipmunkofdoom2 avatar Oct 14 '23 11:10 chipmunkofdoom2

Yup; there are a few moving parts here - not much, but more than I wanted to rush and screw up, hence he omission. Consider me suitably poked.

mgravell avatar Oct 14 '23 11:10 mgravell

Agreed on the above, better wait til you can do it right as opposed to doing it twice (or more). Thanks for taking a look, I appreciate all your hard work on the project.

chipmunkofdoom2 avatar Oct 14 '23 15:10 chipmunkofdoom2

I just subscribed for this issue and will be happy to see QueryUnbufferedAsync<Customer, User, T1, T2, ..., Customer>(...) API overloads in some future version of Dapper.

Thanks for your commitment! :)

deyan-yosifov avatar Mar 07 '24 13:03 deyan-yosifov