원클릭으로
dapper
Use when writing read-optimized queries with Dapper alongside EF Core.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Use when writing read-optimized queries with Dapper alongside EF Core.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Use when adding caching to .NET APIs or optimizing response times with distributed cache, output cache, or ETags.
Use when configuring API response formats, custom formatters, or Accept header handling.
Use when building controller-based REST APIs with action results, model binding, or MediatR integration.
Use when creating RESTful API controllers with MediatR dispatch and ProblemDetails error responses.
Use when designing gRPC services, proto files, or adding gRPC-Web or JSON transcoding.
Use when building minimal API endpoints with route groups, filters, or TypedResults.
| name | dapper |
| description | Use when writing read-optimized queries with Dapper alongside EF Core. |
| metadata | {"category":"data","agent":"ef-specialist","when-to-use":"When writing read-optimized SQL queries using Dapper alongside EF Core"} |
| Scenario | Use |
|---|---|
| Complex read queries with joins | Dapper |
| Reporting and aggregation | Dapper |
| Bulk insert/update | Dapper |
| CRUD operations | EF Core |
| Change tracking | EF Core |
| Migrations | EF Core |
namespace {Company}.{Domain}.Infrastructure.Queries;
public sealed class OrderQueryService(IDbConnectionFactory connectionFactory)
{
public async Task<OrderDetailDto?> GetByIdAsync(Guid id, CancellationToken ct)
{
using var connection = connectionFactory.Create();
const string sql = """
SELECT o.Id, o.CustomerName, o.Total, o.Status, o.CreatedAt
FROM Orders o
WHERE o.Id = @Id
""";
return await connection.QuerySingleOrDefaultAsync<OrderDetailDto>(
new CommandDefinition(sql, new { Id = id }, cancellationToken: ct));
}
}
public async Task<IEnumerable<OrderWithItemsDto>> GetOrdersWithItemsAsync(
CancellationToken ct)
{
using var connection = connectionFactory.Create();
const string sql = """
SELECT o.Id, o.CustomerName, o.Total,
i.Id AS ItemId, i.ProductName, i.Quantity, i.UnitPrice
FROM Orders o
LEFT JOIN OrderItems i ON i.OrderId = o.Id
ORDER BY o.CreatedAt DESC
""";
var lookup = new Dictionary<Guid, OrderWithItemsDto>();
await connection.QueryAsync<OrderWithItemsDto, OrderItemDto, OrderWithItemsDto>(
new CommandDefinition(sql, cancellationToken: ct),
(order, item) =>
{
if (!lookup.TryGetValue(order.Id, out var existing))
{
existing = order;
existing.Items = [];
lookup[order.Id] = existing;
}
if (item is not null)
existing.Items.Add(item);
return existing;
},
splitOn: "ItemId");
return lookup.Values;
}
public async Task<PaginatedResult<OrderSummaryDto>> GetPaginatedAsync(
string? search, string? status, int page, int pageSize, CancellationToken ct)
{
using var connection = connectionFactory.Create();
var builder = new SqlBuilder();
var countTemplate = builder.AddTemplate(
"SELECT COUNT(*) FROM Orders o /**where**/");
var selectTemplate = builder.AddTemplate("""
SELECT o.Id, o.CustomerName, o.Total, o.Status, o.CreatedAt
FROM Orders o /**where**/ /**orderby**/
OFFSET @Offset ROWS FETCH NEXT @PageSize ROWS ONLY
""");
if (!string.IsNullOrEmpty(search))
builder.Where("o.CustomerName LIKE @Search", new { Search = $"%{search}%" });
if (!string.IsNullOrEmpty(status))
builder.Where("o.Status = @Status", new { Status = status });
builder.OrderBy("o.CreatedAt DESC");
var total = await connection.ExecuteScalarAsync<int>(
new CommandDefinition(countTemplate.RawSql, countTemplate.Parameters,
cancellationToken: ct));
var items = await connection.QueryAsync<OrderSummaryDto>(
new CommandDefinition(selectTemplate.RawSql,
new DynamicParameters(selectTemplate.Parameters)
{
{ "Offset", (page - 1) * pageSize },
{ "PageSize", pageSize }
}, cancellationToken: ct));
return new PaginatedResult<OrderSummaryDto>(items.ToList(), total, page, pageSize);
}
public interface IDbConnectionFactory
{
IDbConnection Create();
}
public sealed class SqlConnectionFactory(IOptions<DatabaseOptions> options)
: IDbConnectionFactory
{
public IDbConnection Create() =>
new SqlConnection(options.Value.ConnectionString);
}
services.AddSingleton<IDbConnectionFactory, SqlConnectionFactory>();
services.AddScoped<OrderQueryService>();
| Anti-Pattern | Correct Approach |
|---|---|
| String concatenation for SQL | Use SqlBuilder or parameterized queries |
| Not disposing connections | using var connection = ... |
| Using Dapper for simple CRUD | Use EF Core for CRUD |
| Forgetting CancellationToken | Pass via CommandDefinition |
grep -r "Dapper\|SqlMapper\|QueryAsync\|SqlBuilder" --include="*.cs"
grep -r "IDbConnection\|SqlConnection" --include="*.cs"
Dapper and Dapper.SqlBuilder NuGet packagesIDbConnectionFactory if not already present