Dapper: V2 API refactors

Created on 11 Jul 2019  路  10Comments  路  Source: StackExchange/Dapper

So v2 is going to have to happen at some point; we will want to do as much as we can at one "break", so: thoughts here:

Virtually definite

  • [ ] unify strong-name
  • [ ] remove overload-'splosion caused by gradual growth of overloads
  • [ ] move from IDbConnection etc to DbConnection for the async methods
  • [ ] make sure CancellationToken is used on all async methods
  • [x] drop TFM support for netstandard1.3
  • [x] remove the SqlClient dependency (need to fix one API only)

Virtually definite (additive; not a break)

  • [ ] new IAsyncEnumerable<T> API

Maybe

  • [ ] move from IDbConnection etc to DbConnection throughout
  • [ ] move from Task<T> to ValueTask<T> throughout
  • [ ] move the existing QueryAsync<T> API to IAsyncEnumerable<T> (was Task<IEnumerable<T>>)

Maybe (additive; not a break)

  • [ ] add TFM for netcoreapp3.0 and review what we can exploit
  • [ ] support for new ADO.NET batching API

Wouldn't rule it out (somewhere between "maybe" and "nope")

  • [ ] [PooledAwait](https://github.com/mgravell/PooledAwait) (internal implementation detail, but adds a dependency; works best with ValueTask<T>, but can have benefits on Task<T> too)

other ideas?

api breaking-change v3.0

Most helpful comment

Don't know if it's the correct place, but not having the TypeMapper a singleton would be very helpful. The current behavior doesn't allow your application to be connected to two different databases at the same time.
Maybe attach these TypeMappers on the DbConnection ?
Thanks

All 10 comments

heh, turns out we've already started this here - but: always good to get another round of input!

Feels like there might be some value in keeping a QueryAsync<T> (or equivalent) that returns Task<IEnumerable<T>>. The case of "I don't want to block on the query, but I don't want to proceed until I've got all the results" (as compared to "I don't want to block, but can proceed once the first row is available") doesn't seem un(reasonble|common). It _kind_ of maps to buffered/not-buffered, but I don't know that that would make sense as a separate set of methods rather than the parameter it is now.

I, of course, am tempted to want the MarkedSqlString-stuff added (opt-in, naturally) since it's so damn useful. Don't know if there's a clean way to do that though, the SO impl probably has some MS SQL Server assumptions.

That's actually very relevant, @kevin-montrose - because we could also take the opportunity to clarify buffered Vs non-buffered. Buffered => List<T> / ValueTask<List<T>>, non-buffered => I[Async]Enumerable<T>

There are many times where my method's return type is Task<ImmutableArray<Foo>> and I don't want to buffer to a List<Foo> since I have to do .ToImmutableArray() myself anyway. It would be cool if somehow the immutable array builder could be the buffer itself.

@jnm2 we'd still have a non-buffered API - it would just be more explicit in the naming; in your case, you'd presumably just write an extension method that wraps that up for you?

That sounds good.

Don't know if it's the correct place, but not having the TypeMapper a singleton would be very helpful. The current behavior doesn't allow your application to be connected to two different databases at the same time.
Maybe attach these TypeMappers on the DbConnection ?
Thanks

@vdaron valid observation, but not quite sure what that would look like in terms of usage; presumably we'd need some kind of config state, so is that an argument? or a source? i.e. is it

```c#
var data = connection.Query("...", ... , someConfigArg: configParam);

or is it:

```c#
var data = config.Query<T>(connection, "...", ... );

or is it something else? I think that's a valid discussion, but probably one to split out separately. If there is a case to add it as a parameter, for example, that would be better done "sooner" than "later".

In terms of usage, I would prefer the first one.

One other option would be to have a DapperConnection inheriting from IDbConnection and encapsulating a DbConnection , but it's probably a little too much :-)

One other option would be to have a DapperConnection inheriting from IDbConnection and encapsulating a DbConnection

My concern there is that a lot of apps allocate lots of connections, which makes that - well, not impossible, but perhaps undesirable.

Was this page helpful?
0 / 5 - 0 ratings