Skip to content

Class DbCommandAttribute ​

Namespace: Momentum.Extensions.Abstractions.Dapper
Assembly: Momentum.Extensions.Abstractions.dll

Marks a class for database command code generation, creating efficient data access patterns with minimal boilerplate.

csharp
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public sealed class DbCommandAttribute : Attribute

Inheritance ​

object ← Attribute ← DbCommandAttribute

Inherited Members ​

Attribute.GetCustomAttributes(MemberInfo, Type), Attribute.GetCustomAttributes(MemberInfo, Type, bool), Attribute.GetCustomAttributes(MemberInfo), Attribute.GetCustomAttributes(MemberInfo, bool), Attribute.IsDefined(MemberInfo, Type), Attribute.IsDefined(MemberInfo, Type, bool), Attribute.GetCustomAttribute(MemberInfo, Type), Attribute.GetCustomAttribute(MemberInfo, Type, bool), Attribute.GetCustomAttributes(ParameterInfo), Attribute.GetCustomAttributes(ParameterInfo, Type), Attribute.GetCustomAttributes(ParameterInfo, Type, bool), Attribute.GetCustomAttributes(ParameterInfo, bool), Attribute.IsDefined(ParameterInfo, Type), Attribute.IsDefined(ParameterInfo, Type, bool), Attribute.GetCustomAttribute(ParameterInfo, Type), Attribute.GetCustomAttribute(ParameterInfo, Type, bool), Attribute.GetCustomAttributes(Module, Type), Attribute.GetCustomAttributes(Module), Attribute.GetCustomAttributes(Module, bool), Attribute.GetCustomAttributes(Module, Type, bool), Attribute.IsDefined(Module, Type), Attribute.IsDefined(Module, Type, bool), Attribute.GetCustomAttribute(Module, Type), Attribute.GetCustomAttribute(Module, Type, bool), Attribute.GetCustomAttributes(Assembly, Type), Attribute.GetCustomAttributes(Assembly, Type, bool), Attribute.GetCustomAttributes(Assembly), Attribute.GetCustomAttributes(Assembly, bool), Attribute.IsDefined(Assembly, Type), Attribute.IsDefined(Assembly, Type, bool), Attribute.GetCustomAttribute(Assembly, Type), Attribute.GetCustomAttribute(Assembly, Type, bool), Attribute.Equals(object?), Attribute.GetHashCode(), Attribute.Match(object?), Attribute.IsDefaultAttribute(), Attribute.TypeId, object.GetType(), object.ToString(), object.Equals(object?), object.Equals(object?, object?), object.ReferenceEquals(object?, object?), object.GetHashCode()

Examples ​

DbCommand Attribute Examples ​

Basic Stored Procedure Command ​

csharp
[DbCommand(sp: "create_user")]
public record CreateUserCommand(string Name, string Email) : ICommand<int>;

// Generated usage:
var command = new CreateUserCommand("John Doe", "john@example.com");
var userId = await CreateUserCommandHandler.HandleAsync(command, dataSource, cancellationToken);

SQL Query with Custom Parameter Names ​

csharp
[DbCommand(sql: "SELECT * FROM users WHERE created_date >= @from_date AND status = @user_status", 
          paramsCase: DbParamsCase.SnakeCase)]
public record GetRecentUsersQuery(
    [Column("from_date")] DateTime Since,
    [Column("user_status")] string Status) : IQuery<IEnumerable<User>>;

// Generated ToDbParams() creates: { from_date = Since, user_status = Status }

Database Function Call ​

csharp
[DbCommand(fn: "$get_user_orders")]
public record GetUserOrdersQuery(int UserId, bool IncludeInactive = false) : IQuery<IEnumerable<Order>>;

// Generated SQL: "SELECT * FROM get_user_orders(@UserId, @IncludeInactive)"

Non-Query Command (INSERT/UPDATE/DELETE) ​

csharp
[DbCommand(sql: "UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE id = @UserId", nonQuery: true)]
public record UpdateLastLoginCommand(int UserId) : ICommand<int>;

// Returns number of affected rows

Repository Integration Pattern ​

csharp
public class UserRepository
{
    private readonly DbDataSource _dataSource;
    
    public UserRepository(DbDataSource dataSource) => _dataSource = dataSource;
    
    public async Task<int> CreateUserAsync(string name, string email, CancellationToken ct = default)
    {
        var command = new CreateUserCommand(name, email);
        return await CreateUserCommandHandler.HandleAsync(command, _dataSource, ct);
    }
    
    public async Task<IEnumerable<User>> GetRecentUsersAsync(DateTime since, string status, CancellationToken ct = default)
    {
        var query = new GetRecentUsersQuery(since, status);
        return await GetRecentUsersQueryHandler.HandleAsync(query, _dataSource, ct);
    }
}

Dependency Injection with Named Data Sources ​

csharp
[DbCommand(sp: "archive_old_orders", dataSource: "ArchiveDatabase")]
public record ArchiveOldOrdersCommand(DateTime OlderThan) : ICommand<int>;

// Generated handler will resolve keyed service: [FromKeyedServices("ArchiveDatabase")] DbDataSource dataSource

Remarks ​

Important: Only one of sp, sql, or fn should be specified. If multiple are provided, the source generator will emit a diagnostic error.

Constructors ​

DbCommandAttribute(string?, string?, string?, DbParamsCase, bool, string?) ​

Marks a class for database command code generation, creating efficient data access patterns with minimal boilerplate.

csharp
public DbCommandAttribute(string? sp = null, string? sql = null, string? fn = null, DbParamsCase paramsCase = DbParamsCase.Unset, bool nonQuery = false, string? dataSource = null)

Parameters ​

sp string?

The name of the stored procedure to execute. Mutually exclusive with sql and fn. Only one of these three parameters may be specified.

sql string?

The SQL query text to execute. Mutually exclusive with sp and fn. Only one of these three parameters may be specified.

fn string?

The database function name to call. Parameters are auto-generated from record properties. Mutually exclusive with sp and sql. Only one of these three parameters may be specified. Use '$' prefix (e.g., "$get_user_orders") to generate "SELECT * FROM get_user_orders(...)" syntax.

paramsCase DbParamsCase

Specifies how property names are converted to database parameter names. Defaults to global MSBuild configuration.

nonQuery bool

Controls the execution strategy for database commands. Default is false.

If true: Uses Dapper's ExecuteAsync() for commands returning row counts (INSERT/UPDATE/DELETE operations). If false: Uses appropriate query methods (QueryAsync, QueryFirstOrDefaultAsync, ExecuteScalarAsync) based on the return type.

dataSource string?

The keyed data source name for dependency injection. If null, uses the default registered data source.

Examples ​

DbCommand Attribute Examples ​

Basic Stored Procedure Command ​

csharp
[DbCommand(sp: "create_user")]
public record CreateUserCommand(string Name, string Email) : ICommand<int>;

// Generated usage:
var command = new CreateUserCommand("John Doe", "john@example.com");
var userId = await CreateUserCommandHandler.HandleAsync(command, dataSource, cancellationToken);

SQL Query with Custom Parameter Names ​

csharp
[DbCommand(sql: "SELECT * FROM users WHERE created_date >= @from_date AND status = @user_status", 
          paramsCase: DbParamsCase.SnakeCase)]
public record GetRecentUsersQuery(
    [Column("from_date")] DateTime Since,
    [Column("user_status")] string Status) : IQuery<IEnumerable<User>>;

// Generated ToDbParams() creates: { from_date = Since, user_status = Status }

Database Function Call ​

csharp
[DbCommand(fn: "$get_user_orders")]
public record GetUserOrdersQuery(int UserId, bool IncludeInactive = false) : IQuery<IEnumerable<Order>>;

// Generated SQL: "SELECT * FROM get_user_orders(@UserId, @IncludeInactive)"

Non-Query Command (INSERT/UPDATE/DELETE) ​

csharp
[DbCommand(sql: "UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE id = @UserId", nonQuery: true)]
public record UpdateLastLoginCommand(int UserId) : ICommand<int>;

// Returns number of affected rows

Repository Integration Pattern ​

csharp
public class UserRepository
{
    private readonly DbDataSource _dataSource;
    
    public UserRepository(DbDataSource dataSource) => _dataSource = dataSource;
    
    public async Task<int> CreateUserAsync(string name, string email, CancellationToken ct = default)
    {
        var command = new CreateUserCommand(name, email);
        return await CreateUserCommandHandler.HandleAsync(command, _dataSource, ct);
    }
    
    public async Task<IEnumerable<User>> GetRecentUsersAsync(DateTime since, string status, CancellationToken ct = default)
    {
        var query = new GetRecentUsersQuery(since, status);
        return await GetRecentUsersQueryHandler.HandleAsync(query, _dataSource, ct);
    }
}

Dependency Injection with Named Data Sources ​

csharp
[DbCommand(sp: "archive_old_orders", dataSource: "ArchiveDatabase")]
public record ArchiveOldOrdersCommand(DateTime OlderThan) : ICommand<int>;

// Generated handler will resolve keyed service: [FromKeyedServices("ArchiveDatabase")] DbDataSource dataSource

Remarks ​

Important: Only one of sp, sql, or fn should be specified. If multiple are provided, the source generator will emit a diagnostic error.

Properties ​

DataSource ​

Gets the data source key.

csharp
public string? DataSource { get; }

Property Value ​

string?

Fn ​

If set, a command handler will be generated using this function SQL query. Parameters will be automatically appended based on record properties.

csharp
public string? Fn { get; }

Property Value ​

string?

NonQuery ​

Indicates the nature of the command. This flag primarily influences behavior for ICommand<int/long>.

If true:
- For ICommand<int/long>: The generated handler will use Dapper's ExecuteAsync (expecting rows affected).
- For ICommand<TResult> where TResult is not int: A warning will be issued by the source generator, as using NonQuery=true with a command expecting a specific data structure is atypical. The handler will default to execute a Query or QueryFirstOrDefault call and return default(TResult).

If false:
- For ICommand<int>: The generated handler will use Dapper's ExecuteScalarAsync<int> (expecting a scalar integer query result).
- For ICommand<TResult> where TResult is not int: The handler will perform a query (e.g., QueryFirstOrDefault or Query).

csharp
public bool NonQuery { get; }

Property Value ​

bool

ParamsCase ​

Specifies how property names are converted to database parameter names in the generated ToDbParams() method.

- : Uses the global default specified by the DbCommandDefaultParamCase MSBuild property

- : Uses property names as-is without any conversion

- : Converts property names to snake_case (e.g., FirstName -> first_name)

Individual properties can override this behavior using the [Column("custom_name")] attribute.

csharp
public DbParamsCase ParamsCase { get; }

Property Value ​

DbParamsCase

Sp ​

If set, a command handler will be generated using this stored procedure.

csharp
public string? Sp { get; }

Property Value ​

string?

Sql ​

If set, a command handler will be generated using this SQL query.

csharp
public string? Sql { get; }

Property Value ​

string?