--- title: "Transactions" description: "Use transactions to group database operations atomically." canonical: "https://roomsharp.dev/docs/v0.5.3/transactions" source: "src/content/v0.5.3/transactions.mdx" --- # Transactions RoomSharp provides multiple ways to work with transactions for atomic database operations. ## Transaction Helpers Use the built-in transaction helpers from `RoomDatabase`: - `RunInTransaction(Action)` - Synchronous action - `RunInTransaction(Func)` - Synchronous function with return value - `RunInTransactionAsync(Func)` - Async action - `RunInTransactionAsync(Func>)` - Async function with return value Async overloads also accept `CancellationToken`, so waiting for the transaction gate and opening the transaction can be cancelled by the caller. ```csharp // Synchronous db.RunInTransaction(() => { db.UserDao.Insert(user1); db.UserDao.Insert(user2); }); // With return value var count = db.RunInTransaction(() => { db.UserDao.Insert(user1); return db.UserDao.GetCount(); }); // Async await db.RunInTransactionAsync(async () => { await db.UserDao.InsertAsync(user1); await db.UserDao.InsertAsync(user2); }); // Async with return value var result = await db.RunInTransactionAsync(async () => { await db.UserDao.InsertAsync(user1); return await db.UserDao.FindByIdAsync(user1.Id); }); ``` ## [Transaction] Attribute Mark DAO methods with `[Transaction]` to have the generator wrap the emitted body in the appropriate helper (sync/async). The code generator handles `Task`, `Task`, and synchronous methods automatically. ```csharp [Dao] public interface IUserDao { [Insert] long Insert(User user); [Update] int Update(User user); [Query("SELECT * FROM users WHERE Email = :email")] Task FindByEmailAsync(string email); [Transaction] async Task UpsertAsync(User user) { var existing = await FindByEmailAsync(user.Email); if (existing is null) { return Insert(user); } existing.Name = user.Name; Update(existing); return existing.Id; } [Query("DELETE FROM users WHERE IsActive = 0")] Task DeleteInactiveAsync(); [Transaction] async Task ReplaceAllAsync(IEnumerable users) { await DeleteInactiveAsync(); var count = 0; foreach (var user in users) { Insert(user); count++; } return count; } } ``` The `[Transaction]` attribute is ideal for methods that combine multiple DAO operations that must succeed or fail together. `[Transaction]` cannot be applied to `IAsyncEnumerable` streaming DAO methods. Streaming keeps the data reader alive after the method returns, so the generator reports a compile-time diagnostic instead of creating an unclear transaction lifetime. ## Rollback Behavior Transactions automatically rollback when: - An exception is thrown within the transaction scope - The transaction is not explicitly committed ```csharp try { await db.RunInTransactionAsync(async () => { await db.UserDao.InsertAsync(user1); // This will throw, causing rollback throw new InvalidOperationException("Something went wrong"); await db.UserDao.InsertAsync(user2); // Never executed }); } catch (InvalidOperationException) { // user1 was NOT inserted due to rollback } ``` ## UnitOfWork (Parallel Mode) When using Parallel concurrency mode, use `BeginUnitOfWorkAsync` for explicit transaction control: ```csharp await using var uow = await db.BeginUnitOfWorkAsync(); try { await db.UserDao.InsertAsync(new User { Email = "a@b.com" }); await db.UserDao.InsertAsync(new User { Email = "b@c.com" }); await uow.CommitAsync(); } catch { // Automatic rollback on dispose if not committed } ``` In Parallel mode, parallel DAO calls inside an active UnitOfWork reuse the ambient session and run serially. Do not attempt parallel execution within the same UnitOfWork. ## Best Practices 1. **Keep transactions short** - Long-running transactions can cause lock contention 2. **Use `[Transaction]` for DAO methods** - Let the generator handle the wrapping 3. **Handle exceptions properly** - Always wrap transaction code in try-catch when you need to handle failures 4. **Avoid nested transactions** - RoomSharp uses savepoints for nested calls, but it's best to design for single transaction scope 5. **Test rollback scenarios** - Ensure your application handles transaction failures gracefully