---
title: "Attributes Reference"
description: "Comprehensive guide to all RoomSharp attributes"
canonical: "https://roomsharp.dev/docs/v0.4.7/attributes"
source: "src/content/v0.4.7/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 |