--- title: "Attributes Reference" description: "Comprehensive guide to all RoomSharp attributes" canonical: "https://roomsharp.dev/docs/v0.5.3/attributes" source: "src/content/v0.5.3/attributes.mdx" --- # Attributes Reference This page provides a complete reference for all attributes in RoomSharp. --- ## Entity Mapping Attributes ### `[Entity]` Marks a class as a database entity (table). ```csharp [Entity(TableName = "users")] public class User { ... } ``` **Properties:** | Property | Type | Description | |----------|------|-------------| | `TableName` | `string` | Database table name (defaults to class name) | --- ### `[PrimaryKey]` Marks a property as the primary key. ```csharp [PrimaryKey(AutoGenerate = true)] public long Id { get; set; } ``` **Properties:** | Property | Type | Default | Description | |----------|------|---------|-------------| | `AutoGenerate` | `bool` | `false` | Auto-increment the key value | --- ### `[ColumnInfo]` Customizes column mapping and type affinity. ```csharp [ColumnInfo(Name = "user_email", TypeAffinity = "TEXT")] public string Email { get; set; } ``` **Properties:** | Property | Type | Description | |----------|------|-------------| | `Name` | `string` | Database column name | | `TypeAffinity` | `string` | SQLite type affinity (TEXT, INTEGER, REAL, BLOB) | --- ### `[Unique]` Marks a property as having a unique constraint. ```csharp [Unique] public required string Email { get; set; } ``` For composite unique constraints, use the `[Index]` attribute with `Unique = true`. --- ### `[Index]` Defines an index on the entity. ```csharp [Entity(TableName = "users")] [Index(Value = ["Email"], Unique = true)] [Index(Value = ["LastName", "FirstName"])] public class User { ... } ``` **Properties:** | Property | Type | Description | |----------|------|-------------| | `Value` | `string[]` | Column names to include in the index | | `Unique` | `bool` | Whether the index enforces uniqueness | --- ### `[Ignore]` Excludes a property from database mapping. ```csharp [Ignore] public string TempData { get; set; } ``` --- ### `[ForeignKey]` Defines a foreign key constraint. ```csharp [ForeignKey(Entity = typeof(User), OnDelete = ForeignKeyAction.Cascade)] public long UserId { get; set; } ``` **Properties:** | Property | Type | Description | |----------|------|-------------| | `Entity` | `Type` | Referenced entity type | | `OnDelete` | `ForeignKeyAction` | Action on delete (Cascade, Restrict, SetNull, NoAction) | | `OnUpdate` | `ForeignKeyAction` | Action on update | --- ### `[Embedded]` Embeds another object's properties as columns in the parent entity. ```csharp [Entity(TableName = "orders")] public class Order { [PrimaryKey(AutoGenerate = true)] public long Id { get; set; } [Embedded(Prefix = "billing_")] public Address BillingAddress { get; set; } [Embedded(Prefix = "shipping_")] public Address ShippingAddress { get; set; } } public class Address { public string Street { get; set; } public string City { get; set; } public string PostalCode { get; set; } } ``` **Properties:** | Property | Type | Description | |----------|------|-------------| | `Prefix` | `string?` | Column name prefix (e.g., `billing_street`, `billing_city`) | Embedded objects are flattened into the parent table. Use `Prefix` to disambiguate multiple embedded objects of the same type. **Usage in DTO Projections:** ```csharp public class UserWithPosts { [Embedded] public User User { get; set; } = default!; public long Id => User.Id; [Relation(Entity = typeof(Post), ParentColumn = "Id", EntityColumn = "UserId")] public List Posts { get; set; } = new(); } ``` --- ### `[DatabaseView]` Defines a database view entity. ```csharp [DatabaseView(ViewName = "active_users", Query = "SELECT * FROM users WHERE IsActive = 1")] public class ActiveUser { public long Id { get; set; } public string Email { get; set; } public string Name { get; set; } } ``` **Properties:** | Property | Type | Description | |----------|------|-------------| | `ViewName` | `string?` | View name in the database | | `Query` | `string?` | SQL query that defines the view | Views are read-only. You cannot use `[Insert]`, `[Update]`, or `[Delete]` on view entities. --- ## DAO Operation Attributes ### `[Dao]` Marks an interface as a Data Access Object. ```csharp [Dao] public interface IUserDao { ... } ``` --- ### `[Query]` Defines a SQL query method. ```csharp [Query("SELECT * FROM users WHERE Id = :id")] Task GetById(long id); [Query("SELECT * FROM users WHERE Email LIKE :pattern")] Task> SearchByEmail(string pattern); [Query("SELECT COUNT(*) FROM users")] Task GetCount(); ``` Use `:paramName` for named parameters. They map to method parameter names. --- ### `[Insert]` Defines an insert method with optional conflict resolution. ```csharp [Insert] long Insert(User user); [Insert] long InsertAll(params User[] users); [Insert(OnConflict = OnConflictStrategy.Replace)] long Upsert(User user); ``` **Properties:** | Property | Type | Default | Description | |----------|------|---------|-------------| | `OnConflict` | `OnConflictStrategy` | `Abort` | Conflict resolution strategy | #### `OnConflictStrategy` Enum | Value | Description | |-------|-------------| | `Abort` | Abort the operation and rollback (default) | | `Replace` | Replace the existing row with the new values | | `Ignore` | Silently ignore the conflict, keep existing row | | `Fail` | Fail immediately without rollback | | `Rollback` | Rollback to the last commit point | **Example with Replace:** ```csharp [Insert(OnConflict = OnConflictStrategy.Replace)] long UpsertUser(User user); // Creates a new user or replaces existing one based on primary key db.UserDao.UpsertUser(new User { Id = 1, Email = "new@email.com", Name = "Updated" }); ``` --- ### `[Upsert]` Defines an upsert (insert or update) method. ```csharp [Upsert] long Upsert(User user); [Upsert] Task UpsertAsync(User user); ``` `[Upsert]` is equivalent to `[Insert(OnConflict = OnConflictStrategy.Replace)]` but more explicit. --- ### `[BulkInsert]` Defines a high-performance bulk insert method. ```csharp [BulkInsert] long InsertBulk(IEnumerable users); [BulkInsert(BatchSize = 5000)] long InsertLargeBatch(IEnumerable users); [BulkInsert] Task InsertBulkAsync(IAsyncEnumerable users); ``` **Properties:** | Property | Type | Default | Description | |----------|------|---------|-------------| | `BatchSize` | `int` | `1000` | Number of rows per batch | `BulkInsert` is optimized for large datasets. Use `IAsyncEnumerable` for streaming data without loading everything into memory. **Provider-Specific Optimizations:** | Provider | Method | Notes | |----------|--------|-------| | SQLite | Multi-value INSERT | Batched single statements | | PostgreSQL | COPY / unnest | Uses COPY or unnest for bulk loading | | MySQL | Multi-value INSERT | Batched single statements | | SQL Server | SqlBulkCopy | Native bulk copy API | --- ### `[Update]` Defines an update method. ```csharp [Update] int Update(User user); [Update] Task UpdateAsync(User user); ``` --- ### `[Delete]` Defines a delete method. ```csharp [Delete] int Delete(User user); [Delete] Task DeleteAsync(User user); ``` --- ### `[Transaction]` Wraps a method in a database transaction. ```csharp [Transaction] public async Task TransferAsync(long fromId, long toId, decimal amount) { var from = await GetByIdAsync(fromId); var to = await GetByIdAsync(toId); from.Balance -= amount; to.Balance += amount; await UpdateAsync(from); await UpdateAsync(to); } ``` `[Transaction]` is applied to interface methods with bodies (default interface methods). The source generator wraps the emitted body in the appropriate transaction helper. --- ## Database Configuration Attributes ### `[Database]` Marks a class as the database entry point. ```csharp [Database(Version = 1, Entities = [typeof(User), typeof(Order)])] public abstract class AppDatabase : RoomDatabase { public abstract IUserDao UserDao { get; } public abstract IOrderDao OrderDao { get; } } ``` **Properties:** | Property | Type | Description | |----------|------|-------------| | `Version` | `int` | Database schema version (for migrations) | | `Entities` | `Type[]` | Entity types included in this database | | `ConcurrencyMode` | `ConcurrencyMode` | `Serialized` (default) or `Parallel` | --- ### `[TypeConverter]` Registers a custom type converter at the database level. ```csharp [Database(Version = 1, Entities = [typeof(Post)])] [TypeConverter(typeof(DateTimeTicksConverter))] public abstract class AppDatabase : RoomDatabase { ... } ``` **Property-level usage:** ```csharp [Entity(TableName = "posts")] public class Post { [TypeConverter(ConverterType = typeof(DateTimeTicksConverter))] public DateTime PublishedAt { get; set; } [TypeConverter(ConverterType = typeof(JsonConverter>))] public List Tags { get; set; } } ``` --- ## Relation Attributes ### `[Relation]` Defines a relationship to load related entities. ```csharp public class UserWithPosts { [Embedded] public User User { get; set; } = default!; [Relation(Entity = typeof(Post), ParentColumn = "Id", EntityColumn = "UserId")] public List Posts { get; set; } = new(); } ``` **Properties:** | Property | Type | Description | |----------|------|-------------| | `Entity` | `Type` | Related entity type | | `ParentColumn` | `string` | Column in the parent entity | | `EntityColumn` | `string` | Column in the related entity | --- ## Seeding Attributes ### `[Seeder]` Marks a class as a database seeder with configuration options. ```csharp [Seeder( EntityType = typeof(User), Order = 10, DependsOn = [typeof(RoleSeeder)], Environments = ["Development", "Staging"] )] public sealed class UserSeeder : IRoomSeeder { public string? SeedVersion => "1.0.0"; public async ValueTask SeedAsync(SeederContext ctx) { var dao = ((AppDatabase)ctx.Database).UserDao; if (!await dao.ExistsByEmailAsync("admin@local")) { await dao.InsertAsync(new User { Email = "admin@local", Role = "Admin" }); } ctx.LogMessage("UserSeeder completed"); } } ``` **Properties:** | Property | Type | Default | Description | |----------|------|---------|-------------| | `EntityType` | `Type?` | `null` | Entity type this seeder populates (documentation) | | `Name` | `string?` | `null` | Override seeder name (defaults to class name) | | `Order` | `int` | `0` | Execution order within same dependency level (lower runs first) | | `DependsOn` | `Type[]?` | `null` | Seeder types that must run before this one | | `Environments` | `string[]?` | `null` | Allowed environments (empty = all) | | `RunInTransaction` | `bool` | `true` | Wrap seeding in a transaction | | `Repeatable` | `bool` | `false` | Can re-run based on `SeedVersion` hash | Use `SeedVersion` property in your seeder class to trigger re-runs. When the version changes, the seeder will run again even if it was previously applied. --- ## Migration Attributes ### `[AutoMigration]` Defines an automatic migration between schema versions. ```csharp [Database(Version = 3, Entities = [typeof(User)])] [AutoMigration(From = 1, To = 2, Spec = typeof(UserTableSpec))] [AutoMigration(From = 2, To = 3)] public abstract class AppDatabase : RoomDatabase { ... } ``` **Properties:** | Property | Type | Description | |----------|------|-------------| | `From` | `int` | Starting schema version | | `To` | `int` | Target schema version | | `Spec` | `Type?` | Optional `IAutoMigrationSpec` implementation | --- ### Migration Spec Attributes Use these on `IAutoMigrationSpec` implementations: ```csharp [RenameTable(FromTableName = "old_users", ToTableName = "users")] [DeleteColumn(TableName = "users", ColumnName = "legacy_flag")] public sealed class UserTableSpec : IAutoMigrationSpec { [ColumnRename(TableName = "users", FromColumnName = "full_name", ToColumnName = "name")] public string UsersTable => "users"; } ``` | Attribute | Description | |-----------|-------------| | `[RenameTable]` | Rename a table | | `[DeleteTable]` | Delete a table | | `[AddColumn]` | Add a new column | | `[DeleteColumn]` | Delete a column | | `[ColumnRename]` | Rename a column |