SQLlin supports foreign keys to maintain referential integrity.
1. Enable Foreign Key Enforcement (CRITICAL)
By default, SQLite does not enforce foreign keys. You must explicitly enable it for every connection before creating tables:
database {
PRAGMA_FOREIGN_KEYS(true)
CREATE(UserTable)
CREATE(OrderTable)
}
2. Defining Foreign Keys
Method 1: Column-level (@References)
Recommended for simple, single-column foreign keys.
@References(
tableName = "User",
foreignKeys = ["id"],
trigger = Trigger.ON_DELETE_CASCADE
)
val userId: Long
Method 2: Table-level (@ForeignKeyGroup + @ForeignKey)
Required for composite foreign keys (referencing multiple columns).
@ForeignKeyGroup(
group = 0,
tableName = "Product",
trigger = Trigger.ON_DELETE_CASCADE,
constraintName = "fk_product"
)
data class OrderItem(
@ForeignKey(group = 0, reference = "categoryId") val productCategory: Int,
@ForeignKey(group = 0, reference = "productCode") val productCode: String,
)
3. Supported Triggers
| Trigger | Parent Action | Child Behavior | Requires Nullable? |
|---|
| (Default) | Allow | No change | No |
CASCADE | Allow | Child is deleted/updated | No |
SET_NULL | Allow | Foreign key set to NULL | Yes |
SET_DEFAULT | Allow | Foreign key set to @Default | No |
RESTRICT | Block | Operation fails | No |
// Example of @References
@DBRow
@Serializable
data class Order(
@PrimaryKey(isAutoincrement = true) val id: Long?,
@References(
tableName = "User",
foreignKeys = ["id"],
trigger = Trigger.ON_DELETE_CASCADE
)
val userId: Long,
val amount: Double
)