Skip to content

feat: support Dapper overloads with CommandDefinition #153

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

DeagleGross
Copy link
Collaborator

Current PR adds a support to parse use cases with CommandDefinition.

Usage check

If an user invocation has 2 or more parameters which are 1) cnn; 2) command where it is of type CommandDefinition, then I consider it to be a proper Dapper usage with CommandDefinition.

DapperAnalyzer has built-in argument processing to fix sql / detect buffering etc.

foreach (var arg in op.Arguments)
{
switch (arg.Parameter?.Name)

Unfortunately, it is too complicated to cover many other usages of CommandDefinition, so I only added a case for in-place object creation:

_ = connection.Query<string>(new CommandDefinition(...));

Other cases will work (i.e. CommandDefinition as local variable), but will not have argument processing done.

Generator

Since the Dapper.AOT has its own API, it is very easy to just pass in the same parameters who are the CommandDefinition members. So I just do this for example:

[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\CommandDefinition.input.cs", 32, 24)]
internal static global::System.Threading.Tasks.Task<string?> ExecuteScalarAsync2(this global::System.Data.IDbConnection cnn, global::Dapper.CommandDefinition command)
{
    // Execute, Async, TypedResult, HasParameters, Text, Scalar, KnownParameters
    // takes parameter: <anonymous type: int X>
    // parameter map: X
    // returns data: string
    global::System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(command.CommandText));
    global::System.Diagnostics.Debug.Assert((command.CommandType ?? global::Dapper.DapperAotExtensions.GetCommandType(command.CommandText)) == global::System.Data.CommandType.Text);
    global::System.Diagnostics.Debug.Assert(command.Buffered is false); 
    global::System.Diagnostics.Debug.Assert(command.Parameters is not null);

    return global::Dapper.DapperAotExtensions.Command(cnn, command.Transaction, command.CommandText, command.CommandType ?? default, command.CommandTimeout ?? default, CommandFactory0.Instance).ExecuteScalarAsync<string>(command.Parameters, cancellationToken: command.CancellationToken);

}

CommandDefinition implementation is very convenient for such usage - for example I dont care what CancellationToken to pass in, because if it is not passed into CommandDefinition, it will be simply default. So I just map all members into the underlying SQL API

Tests

Added code-generation + integration tests.

Fixes #112

@DeagleGross DeagleGross requested a review from mgravell May 4, 2025 17:26
@DeagleGross DeagleGross self-assigned this May 4, 2025
@@ -503,32 +503,70 @@ StringSyntaxKind.ConcatenatedString or StringSyntaxKind.FormatString

// we want a common understanding of the setup between the analyzer and generator
internal static Location SharedParseArgsAndFlags(in ParseState ctx, IInvocationOperation op, ref OperationFlags flags, out string? sql,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

put viaCommandDefinition in OperationFlags

global::System.Diagnostics.Debug.Assert(command.Buffered is false);
global::System.Diagnostics.Debug.Assert(command.Parameters is null);

return global::Dapper.DapperAotExtensions.Command(cnn, command.Transaction, command.CommandText, command.CommandType ?? default, command.CommandTimeout ?? default, DefaultCommandFactory).ExecuteScalarAsync<string>(command.Parameters, cancellationToken: command.CancellationToken);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. check if it works at all
  2. if it does not and we cant detect it; we should let user know via analyzer warning / just not generate AOT out of it
  3. if it does - its ok

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if parameters is null - then it is probably fine, we will not fallback to any specific type handler

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support Dapper overloads with CommandDefinition
1 participant