--- title: "Generated Code" description: "Understanding the RoomSharp source-generated database and DAO implementation" canonical: "https://roomsharp.dev/docs/v0.5.4/generated-code" source: "src/content/v0.5.4/generated-code.mdx" --- # Generated Code RoomSharp uses a Roslyn source generator to turn your `[Database]` and `[Dao]` declarations into concrete database and DAO implementations at compile time. The generated code is ordinary C# that is compiled into your application, which means most DAO work happens without runtime proxy generation or runtime SQL model discovery. This page describes the generated code shape in the `0.5.4` line. ## What Gets Generated RoomSharp generates two main kinds of files: | Input | Generated output | |-------|------------------| | `[Database]` abstract class | A concrete `*Impl` database type | | `[Dao]` interface | One DAO implementation per database that exposes the DAO | The generator also emits internal helper fields inside DAO implementations for: - Prepared SQL text. - Parameter-name arrays. - Insert statement plans. - Type mapper caches. - Generated soft-delete restore and hard-delete methods. - Generated transaction wrappers. ## Database Implementations For an abstract database declaration: ```csharp [Database( Version = 2, Entities = [typeof(Note), typeof(Document)], Views = [typeof(NoteSummaryView)], ConcurrencyMode = ConcurrencyMode.Parallel)] public abstract class NotesDatabase : RoomDatabase { public abstract INoteDao NoteDao { get; } public abstract IDocumentDao DocumentDao { get; } } ``` RoomSharp generates a concrete database implementation such as `NotesDatabaseImpl`. Generated database implementations: - Create DAO instances lazily according to the configured DAO instance mode. - Pass the database instance, provider connection, and logger into generated DAOs. - Dispose created DAOs when the database is disposed. - Prefer async disposal when a DAO implements `IAsyncDisposable`. The exact generated shape can vary by `DaoInstanceType`, but the database implementation is responsible for DAO ownership and cleanup. ## DAO Implementations For each DAO interface: ```csharp [Dao] public interface INoteDao { [Insert] Task InsertAsync(Note note); [Query("SELECT * FROM notes ORDER BY Id DESC")] Task> GetAllAsync(); [Query("SELECT Id, Title, CreatedAt FROM note_summaries ORDER BY CreatedAt DESC")] Task> GetSummariesAsync(); } ``` RoomSharp generates an implementation such as `INoteDaoImpl`. Generated DAO methods handle: - Connection/session acquisition. - Transaction awareness. - Command creation and reuse. - Parameter binding. - Reader execution. - Entity or projection mapping. - Runtime lifecycle hooks such as change tracking and statistics. ## Command Strategy Generated DAO code uses `DbSession` rather than holding a shared mutable `DbCommand` field. For a normal async query, the generated shape is conceptually: ```csharp _database.NotifyConnectionUsage(); _database.Statistics.RecordQuery(); var ambientSession = _database.GetCurrentSession(); if (ambientSession is null) { await using var session = await _database.OpenSessionAsync(cancellationToken); using var lease = session.Enter(); var cmd = session.GetOrCreateCommand(sql, _dialect, parameterNames); BindParameters(cmd, values); using var reader = await cmd.ExecuteReaderAsync(cancellationToken); var mapper = GetMapper(reader); // read rows... } else { using var lease = ambientSession.Enter(); var cmd = ambientSession.GetOrCreateCommand(sql, _dialect, parameterNames); BindParameters(cmd, values); using var reader = await cmd.ExecuteReaderAsync(cancellationToken); var mapper = GetMapper(reader); // read rows... } ``` This matters for correctness and performance: - Parallel mode uses session-scoped commands instead of shared commands. - Transactional methods reuse the ambient transaction session. - Serialized transaction paths use runtime helpers to avoid returning a command bound to the wrong connection. - Disposal code is kept small, and `DisposeAsync` avoids an async state machine when no asynchronous work is needed. The generated source may not match the simplified example line-for-line. The important behavior is session ownership, ambient transaction support, and command reuse through `DbSession`. ## Mapping RoomSharp maps rows through generated mapper setup and runtime IL helpers. Generated DAOs keep a `TypeMapperCache` for each entity or projection type returned by the DAO. On first use, the generated code builds a mapper pair for the current reader shape; subsequent reads reuse cached mapper entries. This is why projection queries are efficient: ```csharp public sealed record NoteSummaryView { public long Id { get; set; } public required string Title { get; set; } public DateTime CreatedAt { get; set; } } ``` ```csharp [Query("SELECT Id, Title, CreatedAt FROM note_summaries")] Task> GetSummariesAsync(); ``` The generated DAO maps only the selected columns into `NoteSummaryView`. ## Insert Plans Generated insert methods use prebuilt insert plans instead of rebuilding SQL every call. Depending on the entity and provider, the generator can emit: - A plan that includes the primary key. - A plan that omits an auto-generated primary key. - Returning-column metadata for providers that support returning inserted values. - Provider fallback logic when a direct returning form is not available. Collection inserts and `[BulkInsert]` methods route through the batch insert infrastructure where possible. ## Transactions Methods marked with `[Transaction]` are wrapped in `RunInTransaction` or `RunInTransactionAsync`. ```csharp [Transaction] public async Task CreateAndReadAsync(Note note, CancellationToken cancellationToken) { // generated method body runs inside a database transaction } ``` Generated transaction wrappers pass the DAO method `CancellationToken` into the transaction API when a token is available. That means cancellation applies to the transaction gate and transaction setup, not only to SQL commands inside the body. `[Transaction]` is rejected on `IAsyncEnumerable` DAO methods. Streaming results need a transaction lifetime that extends beyond the method return, so RoomSharp reports a compile-time diagnostic instead of silently generating unsafe code. ## Lifecycle Features Generated DAO code participates in RoomSharp lifecycle features: | Feature | Generated behavior | |---------|--------------------| | `[SoftDelete]` | Generated restore and hard-delete DAO methods where applicable | | Soft-delete query filtering | Generated SELECT query paths inject the configured soft-delete filter | | `[Encrypted]` | Generated insert/update paths encrypt values and SELECT paths decrypt returned entities | | `[Auditable]` | Generated insert/update paths populate audit fields | | Global filters | Generated query paths bind filter parameters after SQL injection | | Reactive tracking | Generated mutation paths notify invalidation/change tracking | ## Database Views Database view models can be used as read-only projections: ```csharp [DatabaseView( ViewName = "note_summaries", Query = "SELECT Id, Title, CreatedAt FROM notes", Managed = true)] public sealed record NoteSummaryView { public long Id { get; set; } public required string Title { get; set; } public DateTime CreatedAt { get; set; } } ``` Generated DAOs can query view models just like DTO projections: ```csharp [Query("SELECT Id, Title, CreatedAt FROM note_summaries ORDER BY CreatedAt DESC")] Task> GetSummariesAsync(); ``` When `Managed = true`, the analyzer validates that the view query is a `SELECT` and matches the projection shape. Schema export and schema validation also include managed views. RoomSharp does not create database views automatically from DAO queries. Create the view in a migration or callback. `Managed = true` makes the view visible to validation and schema export. ## Compile-Time Diagnostics The generator and analyzers report diagnostics during build. Important validation areas include: - Entity shape and primary key metadata. - DAO operation compatibility. - SQL table and column references in `[Query]`. - SQL parameters matching DAO method parameters. - Result type compatibility. - `[Transaction]` misuse on streaming methods. - `[DatabaseView]` query shape and mutation misuse. For example, a query against a missing table fails at build time instead of producing a runtime-only failure: ```csharp [Query("SELECT * FROM missing_table")] Task> GetAsync(); ``` ## Generated Files Location By default, source-generator files are compiler inputs and are not usually committed to your project. In IDEs, you can inspect generated files under: ```text Dependencies └── Analyzers └── RoomSharp.SourceGenerator ``` To emit generated files into a visible folder, add: ```xml true Generated ``` With this enabled, generated files appear under a path similar to: ```text Generated/ └── RoomSharp.SourceGenerator/ └── RoomSharp.SourceGenerator.RoomSourceGenerator/ ├── NotesDatabaseImpl.g.cs └── NotesDatabase/ ├── INoteDaoImpl.g.cs └── IDocumentDaoImpl.g.cs ``` Generated files are overwritten on every build. Use them for inspection and debugging, not as files to edit. ## Debugging Generated Code If generated code behaves unexpectedly: 1. Check build diagnostics first. Most generator issues are reported during compilation. 2. Enable `EmitCompilerGeneratedFiles` and inspect the DAO implementation. 3. Confirm the SQL in `[Query]` uses the actual table, view, and column names. 4. Check whether the database uses `ConcurrencyMode.Serialized` or `ConcurrencyMode.Parallel`. 5. If the method is transactional, check whether the generated method uses the ambient session path. ## Next Steps - [DAO Interfaces](/docs/v0.5.4/dao-interfaces) - Learn what gets generated for each DAO attribute. - [Performance Notes](/docs/v0.5.4/performance) - Understand generated DAO hot paths. - [Transactions](/docs/v0.5.4/transactions) - Understand generated transaction wrappers. - [Lifecycle Features](/docs/v0.5.4/lifecycle-features) - See soft delete, encryption, and audit behavior. - [Error Handling](/docs/v0.5.4/error-handling) - Troubleshoot generator and runtime errors.