Overview
Savvyio.Extensions.Dapper adds the persistence-facing types that let a Savvyio application talk to a relational store through Dapper. It extends Savvyio.Core with an IDapperDataSource abstraction, a default DapperDataSource wrapper that opens and owns an IDbConnection, an abstract DapperDataStore<T, TOptions> base class, and DapperQueryOptions for building Dapper CommandDefinition values.
The package is deliberately small. It gives you the contract and base classes for implementing concrete stores, but it does not ship concrete repositories, object mapping helpers, or dependency injection registration.
Key APIs
IDapperDataSource defines the Dapper-oriented source contract by combining Savvyio's IDataSource abstraction with IDbConnection. Store implementations can depend on this interface and still use the underlying connection with normal Dapper extension methods.
DapperDataSourceOptions configures DapperDataSource through a required ConnectionFactory delegate. Its ValidateOptions() method rejects a missing factory, and the tests cover both the default null state and the valid configured state.
DapperDataSource creates a connection from DapperDataSourceOptions, opens it in the constructor, and forwards core IDbConnection members such as CreateCommand(), BeginTransaction(), ConnectionString, ConnectionTimeout, and State. When disposed, it closes and disposes the wrapped connection.
DapperQueryOptions extends AsyncOptions with CommandText, Parameters, CommandTimeout, CommandFlags, CommandType, and Transaction. Its implicit conversion operator turns the options object into a Dapper CommandDefinition, and the default constructor sets a 30 second timeout, buffered execution, and CommandType.Text.
DapperDataStore<T, TOptions> is the base class consumers derive from to implement actual stores. It constrains TOptions to AsyncOptions, new(), exposes the protected Source, requires async CreateAsync, UpdateAsync, GetByIdAsync, FindAllAsync, and DeleteAsync overrides, and disposes the associated data source when the store itself is disposed.
Basic usage
using System;
using System.Data;
using Codebelt.Extensions.Xunit;
using Dapper;
using Savvyio.Extensions.Dapper;
using Xunit;
namespace MyProject.Tests;
public sealed class DapperQueryOptionsDocumentationTests : Test
{
public DapperQueryOptionsDocumentationTests(ITestOutputHelper output) : base(output)
{
}
[Fact]
public void ToCommandDefinition_ConfiguredQuery_BuildsCommandDefinition()
{
var options = new DapperQueryOptions
{
CommandText = "SELECT * FROM Invoices WHERE CustomerId = @CustomerId",
Parameters = new { CustomerId = 42 },
CommandTimeout = TimeSpan.FromSeconds(15),
CommandType = CommandType.Text,
CommandFlags = CommandFlags.Buffered
};
CommandDefinition command = options;
TestOutput.WriteLine($"{command.CommandText} [{command.CommandTimeout}s]");
Assert.Equal("SELECT * FROM Invoices WHERE CustomerId = @CustomerId", command.CommandText);
Assert.Equal(15, command.CommandTimeout);
Assert.Equal(CommandType.Text, command.CommandType);
Assert.Equal(CommandFlags.Buffered, command.Flags);
Assert.Same(options.Parameters, command.Parameters);
}
}
Use this pattern when your store code wants to define SQL, parameters, timeout, and command behavior once and hand the result to Dapper as a CommandDefinition.
It matters because DapperQueryOptions keeps Dapper command settings in the same Savvyio options model that DapperDataStore<T, TOptions> implementations can already accept.
Installation
dotnet add package Savvyio.Extensions.Dapper
Usage guidance
Adopt this package when your Savvyio application wants concrete data stores to share a common Dapper-oriented base class and query options object instead of repeating raw IDbConnection plumbing in each store. If you only need direct Dapper calls, plain Dapper is simpler, and if you need automapping or Microsoft Dependency Injection integration, Savvyio.Extensions.DapperExtensions or Savvyio.Extensions.DependencyInjection.Dapper are the better fit.
Family packages
- 🏭Savvyio.App
- 📦Savvyio.Commands
- 📦Savvyio.Commands.Messaging
- 📦Savvyio.Core
- 📦Savvyio.Domain
- 📦Savvyio.Domain.EventSourcing
- 📦Savvyio.EventDriven
- 📦Savvyio.EventDriven.Messaging
- 📦Savvyio.Extensions.DapperExtensions
- 📦Savvyio.Extensions.DependencyInjection
- 📦Savvyio.Extensions.DependencyInjection.Dapper
- 📦Savvyio.Extensions.DependencyInjection.DapperExtensions
- 📦Savvyio.Extensions.DependencyInjection.Domain
- 📦Savvyio.Extensions.DependencyInjection.EFCore
- 📦Savvyio.Extensions.DependencyInjection.EFCore.Domain
- 📦Savvyio.Extensions.DependencyInjection.EFCore.Domain.EventSourcing
- 📦Savvyio.Extensions.DependencyInjection.NATS
- 📝Savvyio.Extensions.DependencyInjection.Newtonsoft.Json
- 📦Savvyio.Extensions.DependencyInjection.QueueStorage
- 📦Savvyio.Extensions.DependencyInjection.RabbitMQ
- 📦Savvyio.Extensions.DependencyInjection.SimpleQueueService
- 📝Savvyio.Extensions.DependencyInjection.Text.Json
- 📦Savvyio.Extensions.Dispatchers
- 📦Savvyio.Extensions.EFCore
- 📦Savvyio.Extensions.EFCore.Domain
- 📦Savvyio.Extensions.EFCore.Domain.EventSourcing
- 📦Savvyio.Extensions.NATS
- 📝Savvyio.Extensions.Newtonsoft.Json
- 📦Savvyio.Extensions.QueueStorage
- 📦Savvyio.Extensions.RabbitMQ
- 📦Savvyio.Extensions.SimpleQueueService
- 📝Savvyio.Extensions.Text.Json
- 📦Savvyio.Messaging
- 📦Savvyio.Queries