HasOneAssociation
The HasOneAssociation
indicates a one-to-one connection between two record types, such as each instance of the declaring record “has one” instances of the other record.
struct HasOneAssociation<Origin, Destination>
For example, if your application has one database table for countries, and another for their demographic profiles, you’d declare the association this way:
struct Demographics: TableRecord { }
struct Country: TableRecord {
static let demographics = hasOne(Demographics.self)
}
A HasOneAssociation
should be supported by an SQLite foreign key.
Foreign keys are the recommended way to declare relationships between database tables because not only will SQLite guarantee the integrity of your data, but GRDB will be able to use those foreign keys to automatically configure your associations.
You define the foreign key when you create database tables. For example:
try db.create(table: "country") { t in
t.primaryKey("code", .text) // (1)
t.column("name", .text)
}
try db.create(table: "demographics") { t in
t.autoIncrementedPrimaryKey("id")
t.belongsTo("country", onDelete: .cascade) // (2)
.notNull() // (3)
.unique() // (4)
t.column("population", .integer)
t.column("density", .double)
}
The country table has a primary key.
The
demographics.countryCode
column is used to link a demographic profile to the country it belongs to. This column is indexed in order to ease the selection of the demographics of a country. A foreign key is defined fromdemographics.countryCode
column tocountry.code
, so that SQLite guarantees that no profile refers to a missing country. TheonDelete: .cascade
option has SQLite automatically delete a profile when its country is deleted. See https://sqlite.org/foreignkeys.html#fk_actions for more information.Make the
demographics.countryCode
column not null if you want SQLite to guarantee that all profiles are linked to a country.Create a unique index on the
demographics.countryCode
column in order to guarantee the unicity of any country’s demographics.
The example above uses a string primary for the country table. But generally speaking, all primary keys are supported.
If the database schema does not define foreign keys between tables, you can still use HasOneAssociation
. But your help is needed to define the missing foreign key:
struct Demographics: TableRecord { }
struct Country: TableRecord {
static let demographics = hasOne(Demographics.self, using: ForeignKey(...)
}