--- title: "Generated Code" description: "Understanding what RoomSharp''s source generator creates" canonical: "https://roomsharp.dev/docs/v0.5.3/generated-code" source: "src/content/v0.5.3/generated-code.mdx" --- # Generated Code Understanding what RoomSharp's source generator creates. ## How Code Generation Works RoomSharp uses C# Source Generators to create implementations at compile-time. When you mark interfaces with `[Dao]` and classes with `[Database]`, the generator analyzes your code and produces concrete implementations. ## What Gets Generated ### 1. DAO Implementations For each `[Dao]` interface, RoomSharp generates a concrete class with `Impl` suffix: ```csharp [Dao] public interface IUserDao { [Insert] long Insert(User user); [Query("SELECT * FROM users WHERE Id = :id")] Task GetByIdAsync(long id); } ``` ```csharp public class IUserDaoImpl : IUserDao { private readonly RoomDatabase _database; private readonly ILogger? _logger; public IUserDaoImpl(RoomDatabase database, ILogger? logger) { _database = database; _logger = logger; } public long Insert(User user) { var connection = _database.GetConnection(); using var command = connection.CreateCommand(); command.CommandText = "INSERT INTO users (Email, Name) VALUES (@p0, @p1)"; command.Parameters.Add(CreateParameter("@p0", user.Email)); command.Parameters.Add(CreateParameter("@p1", user.Name)); command.ExecuteNonQuery(); return connection.LastInsertedRowId; } public async Task GetByIdAsync(long id) { var connection = _database.GetConnection(); using var command = connection.CreateCommand(); command.CommandText = "SELECT * FROM users WHERE Id = @p0"; command.Parameters.Add(CreateParameter("@p0", id)); using var reader = await command.ExecuteReaderAsync(); if (await reader.ReadAsync()) { return MapUser(reader); } return null; } private User MapUser(DbDataReader reader) { // IL-based high-performance mapping return ILFactory.MapUser(reader); } } ``` ### 2. Database Implementations For `[Database]` classes, RoomSharp generates the `Impl` version: ```csharp [Database(Version = 1, Entities = [typeof(User)])] public abstract class AppDatabase : RoomDatabase { protected AppDatabase(IDatabaseProvider provider, ILogger? logger = null) : base(provider, logger) { } public abstract IUserDao UserDao { get; } } ``` ```csharp public class AppDatabaseImpl : AppDatabase { private IUserDao? _userDao; public AppDatabaseImpl(IDatabaseProvider provider, ILogger? logger = null) : base(provider, logger) { } public override IUserDao UserDao { get { if (_userDao == null) { _userDao = new IUserDaoImpl(this, Logger); } return _userDao; } } } ``` ### 3. IL-Based Mappers RoomSharp generates high-performance IL code for entity mapping using `ILFactory`: - Zero boxing for value types - Direct property setters (no reflection) - Span-based fast paths - Type-safe reading with `ReaderKind` ## Generated Files Location Generated files appear in your project's `obj/` folder: ``` YourProject/ └── obj/ └── Debug/ └── net8.0/ └── generated/ └── RoomSharp.SourceGenerator/ ├── IUserDaoImpl.g.cs ├── AppDatabaseImpl.g.cs └── EntityMappers.g.cs ``` ## Viewing Generated Code To view generated code in Visual Studio or Rider: 1. Expand the project in Solution Explorer 2. Expand "Dependencies" → "Analyzers" → "RoomSharp.SourceGenerator" 3. View the generated `.g.cs` files > **💡 Tip:** Generated files are regenerated on every build. Don't edit them manually - changes will be lost! ## Compile-Time Validation The source generator performs validation during compilation: - Ensures `[PrimaryKey]` is defined on entities - Validates SQL syntax in `[Query]` attributes - Checks parameter names match method parameters - Verifies return types are compatible with operations - Detects missing or duplicate column mappings ## Performance Optimizations in Generated Code ### Zero Allocations in Hot Loops Batch operations use pre-allocated buffers and reuse prepared statements: ```csharp public void InsertAll(List users) { var engine = new BatchInsertEngine( _database, tableName: "users", columnNames: s_columnNames, // static readonly ImmutableArray bindValues: BindUserValues // static method, zero closure ); engine.ExecuteBatch(users); } ``` ### Static Column Arrays Column names are stored as `static readonly ImmutableArray` for reuse: ```csharp private static readonly ImmutableArray s_columnNames = ImmutableArray.Create("Id", "Email", "Name"); ``` ## Transaction Wrapping Methods with `[Transaction]` are wrapped automatically: ```csharp public async Task UpsertAsync(User user) { return await _database.RunInTransactionAsync(async () => { // Your method body here var existing = await FindByEmailAsync(user.Email); if (existing is null) return Insert(user); existing.Name = user.Name; Update(existing); return existing.Id; }); } ``` When a generated DAO method has a `CancellationToken`, the generated transaction wrapper passes that token into `RunInTransactionAsync` / `RunInTransaction` so cancellation applies to the transaction gate as well as the SQL commands. The generator rejects `[Transaction]` on `IAsyncEnumerable` methods because the transaction lifetime cannot safely be tied to a streaming result after the method returns. ## Debugging Generated Code If you encounter issues with generated code: 1. Check build output for generator warnings/errors 2. View the generated files in the analyzers section 3. Enable detailed generator logging in your project file: ```xml true Generated ``` 4. Clean and rebuild the solution ## Next Steps - [DAO Interfaces](/docs/v0.5.3/dao-interfaces) - Learn what gets generated for different attributes - [Performance Notes](/docs/v0.5.3/performance) - Understand IL-based optimizations - [Error Handling](/docs/v0.5.3/error-handling) - Troubleshoot generator issues