Skip to main content

query-with-dapper

Run raw SQL via Dapper inside an ABP repository for hot-path read/aggregate queries while sharing ABP's unit of work, connection, and transaction. USE FOR: complex or slow queries where EF Core's generated SQL is too slow, hand-written SQL you want full control over, deriving from a DbContext-based DapperRepository and using GetDbConnectionAsync/GetDbTransactionAsync to stay in the current unit of work. DO NOT USE FOR: standard CRUD/LINQ/change tracking/migrations (use ef-core-integration), MongoDB queries (use mongodb-integration), unit-of-work configuration itself (use manage-units-of-work), connection string routing (use configure-connection-strings).

الانتقال إلى التثبيت

معلومات المصدر

المستودع
abpframework/abp-skills
آخر نشاط في المصدر
٢٠ يوليو ٢٠٢٦ في ٠٣:٢٤
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
١٨
التفرعات
٠

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
query-with-dapper
description
Run raw SQL via Dapper inside an ABP repository for hot-path read/aggregate queries while sharing ABP's unit of work, connection, and transaction. USE FOR: complex or slow queries where EF Core's generated SQL is too slow, hand-written SQL you want full control over, deriving from a DbContext-based DapperRepository and using GetDbConnectionAsync/GetDbTransactionAsync to stay in the current unit of work. DO NOT USE FOR: standard CRUD/LINQ/change tracking/migrations (use ef-core-integration), MongoDB queries (use mongodb-integration), unit-of-work configuration itself (use manage-units-of-work), connection string routing (use configure-connection-strings).
license
MIT
# Query with Dapper in ABP ABP's `Volo.Abp.Dapper` integration lets you write raw-SQL repositories with [Dapper](https://github.com/DapperLib/Dapper) while staying inside ABP's unit of work. The integration is **built on top of EF Core**: EF Core stays the primary provider and you reach for Dapper only to fine-tune specific queries for maximum performance. ## When to Use - A heavy read or aggregate query where EF Core's generated SQL is too slow. - SQL you want full hand control over, on a hot path. - You want raw SQL that still participates in ABP's unit of work, connection, and transaction. ## When Not to Use - **Standard CRUD, LINQ, change tracking, entities, migrations** — use ef-core-integration; use it for almost everything. - **MongoDB queries** — use mongodb-integration; the Dapper integration requires an EF Core `DbContext`. - **Configuring the unit of work itself** — use manage-units-of-work (this skill only borrows the ambient UoW). - **Connection string / per-tenant database routing setup** — use configure-connection-strings (Dapper inherits routing from the underlying `DbContext`). ## Workflow ### 1. Choose Dapper vs EF Core - **EF Core (default)** — CRUD, change tracking, LINQ, entities, migrations. Use it for almost everything. - **Dapper** — a heavy read or aggregate query where EF Core's generated SQL is too slow, or SQL you want full hand control over. Dapper is a lightweight, high-performance object mapper for these hot paths. You mix the two in the same app. The Dapper integration requires an EF Core `DbContext` — it borrows that context's connection and transaction, so both share the same unit of work. ### 2. Install the package Run in the folder of the `.csproj` you want the package in (the database/EF Core layer in a layered solution): ```bash abp add-package Volo.Abp.Dapper ``` ### 3. Implement a Dapper repository Derive from `DapperRepository<TDbContext>` (namespace `Volo.Abp.Domain.Repositories.Dapper`), where `TDbContext` is your EF Core `DbContext`. Register it for DI. It implements `IUnitOfWorkEnabled`, so ABP makes the current connection/transaction available in method bodies via dynamic proxying (interception). ```csharp using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Dapper; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Repositories.Dapper; using Volo.Abp.EntityFrameworkCore; public class PersonDapperRepository : DapperRepository<MyAppDbContext>, ITransientDependency { public PersonDapperRepository(IDbContextProvider<MyAppDbContext> dbContextProvider) : base(dbContextProvider) { } public virtual async Task<List<string>> GetAllPersonNamesAsync() { var dbConnection = await GetDbConnectionAsync(); return (await dbConnection.QueryAsync<string>( "select Name from People", transaction: await GetDbTransactionAsync()) ).ToList(); } public virtual async Task<int> UpdatePersonNameAsync(Guid id, string name) { var dbConnection = await GetDbConnectionAsync(); // Always scope a write with a WHERE clause — without it this updates every row. return await dbConnection.ExecuteAsync( "update People set Name = @NewName where Id = @Id", new { Id = id, NewName = name }, await GetDbTransactionAsync()); } } ``` ### 4. Preserve the unit of work + connection resolution The base class hands you the ambient connection and transaction that ABP's unit of work is managing — do not open your own connection: ```csharp public virtual async Task<IDbConnection> GetDbConnectionAsync(); // current UoW connection public virtual async Task<IDbTransaction?> GetDbTransactionAsync(); // current UoW transaction (null if none) ``` Because these come from the shared `IDbContextProvider<TDbContext>`: - **Always pass `await GetDbTransactionAsync()`** to your Dapper calls, so raw SQL participates in the same transaction as EF Core writes — otherwise your Dapper query may not see uncommitted changes and won't roll back with the UoW. - Connection resolution (including multi-tenant per-tenant database routing and `[ConnectionStringName]`) is inherited from the underlying `DbContext`, so Dapper hits the same database EF Core would for that context. - The bare `DbConnection` / `DbTransaction` properties exist but are `[Obsolete]` — use the async methods. Rules: - **Make query methods `virtual`.** Interception (which supplies the connection/transaction) only works on virtual members. - The repository resolves its `DbContext` through `IDbContextProvider<TDbContext>`, which must be a configured ABP EF Core `DbContext` (the startup template configures this for you). ### 5. Layered solution tip Define an `IPersonDapperRepository` interface in the domain layer and implement it in the database/EF Core layer. Inject the interface where you need it, keeping the raw SQL out of the domain and application layers. ## Validation - After `abp add-package Volo.Abp.Dapper`, confirm the package reference appears in the target `.csproj`. - Call a Dapper method inside a unit of work that also does EF Core writes; the query should see those uncommitted writes (proving it shares the connection/transaction) and roll back with the UoW. Dapper won't see EF Core's pending changes while they're still in the `ChangeTracker` — flush them first with `autoSave: true` on the write or by calling `SaveChangesAsync()` before the Dapper query. - Confirm query methods are `virtual` — if interception is missing, `GetDbConnectionAsync()`/`GetDbTransactionAsync()` won't resolve the ambient UoW. ## Common Pitfalls - **Opening your own connection** breaks the shared unit of work. Always use `GetDbConnectionAsync()` / `GetDbTransactionAsync()` from the base class. - **Not passing `await GetDbTransactionAsync()`** to Dapper calls means the raw SQL may not see uncommitted EF Core changes and won't roll back with the UoW. - **Non-`virtual` query methods** skip interception, so the ambient connection/transaction is never supplied. - **Using the bare `DbConnection` / `DbTransaction` properties** — they are `[Obsolete]`; use the async methods. ## See also - ABP Dapper integration docs (`framework/data/dapper`) - ABP EF Core integration docs
عرض على GitHub