DapperLib / DapperLib/Dapper

Concrete initial v3 API change proposal

Open
#1,976 20 comments 41 reactions 1 assignee View on GitHub

@mgravell is already working on this.

Since Oct 12, 2023.

area:api v3.0
Dominant language
C#
Stars
18.4k
Forks
3.7k
Avg merge
5h 8m
Merged PRs (30d)
1

Description

Dapper has grown organically over time, and not all decisions were good ones. We have worked hard to try to avoid runtime or compile-time breaks, but this means we have been constrained by those poor decisions.

I would like to get to work on shipping a V2->V3 transition that fixes this, and get some breaks over and done with. As discussed here, some feature work may be shunted to the AOT project, but we need the right API for things to be effective.

What are we trying to solve?

The key problems in the API in V2 are:

  • the signed/unsigned split is a nuisance - there should be one and only one Dapper if we can achieve that without breaking folks
  • starting from the interfaces (IDbConnection etc) rather than the concrete base types (DbConnection) was a mistake
  • CommandDefinition was well intentioned, but again: a mistake - we should expose cancellation via a standard CancellationToken parameter
  • the shared API between buffered and unbuffered data is suboptimal (at best)
  • we should add support for DbDataSource as a root primitive

Contraints on changes:

  • where possible, we should avoid runtime breaks, and minimize compile-time breaks

Planned implementation

The first big change is: strong name the library and retire Dapper.StrongName; bad call.

My proposal for the code, effectively, is to retire the existing API but leave it in place (so: no missing methods) by removing the this modifier (so they no longer resolve as extension methods), and create a new set of extension methods - probably on a new static class that expose the preferred API, meaning: the shape we want, and the most generalized version only (no hive of forwarded methods with increasing numbers of parameters reflecting our incremental understanding of the required API). Code that is already compiled will continue unchanged using the old methods (the missing this is irrelevant and doesn't break the API). When code is recompiled, it'll resolve to the new methods.

For example:

  public static class SqlMapper {
-     public static IEnumerable<T> Query<T>(this IDbConnection conection, string sql, object? parameters = null, bool buffered = true, ...);
+     public static IEnumerable<T> Query<T>(IDbConnection conection, string sql, object? parameters = null, bool buffered = true, ...);
  }
+  public static class DbConnectionExtensions {
+    public static List<T> Query<T>(DbConnection conection, string sql, object? parameters = null, ...);
+    public static IEnumerable<T> QueryUnbuffered<T>(DbConnection conection, string sql, object? parameters = null, ...);
+    [Obsolete("This call to AsList is no longer required")] // highlight redundant Query<T>(...).AsList() usage as a warning
+    public static List<T> AsList<T>(this List<T> source) => source;
+ }

Key changes:

  • root type changes from IDbConnection to DbConnection
  • buffered is now explicit on the method signature rather than a parameter (see the existing QueryUnbufferedAsync)
  • async methods will gain CancellationToken parameters

However:

  • all code will continue to run without recompile (ignoring the signed/unsigned fun)
  • most code will require zero changes to compile (unless they are explicitly specifying buffered, in which case either a: remove buffered: false, or b: switch to QueryUnbuffered)
  • the change to return List<T> in the default buffered case makes reality explicit; in theory this could change how calling code operates, but this is considered to be a positive thing - for example, foreach will be more efficient if it knows it is starting from List<T> due to duck-typing

We'll need to list out the full proposal set, but before we get too far: I want to gather feedback on the overall shape of this suggestion.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.