ForeignKey
public struct ForeignKey
A ForeignKey helps building associations when GRDB can’t infer a foreign key from the database schema.
Sometimes the database schema does not define any foreign key between two tables. And sometimes, there are several foreign keys from a table to another:
| Table book | | Table person |
| ------------ | | ------------ |
| id | +-->• id |
| authorId •---+ | name |
| translatorId •---+
| title |
When this happens, associations can’t be automatically inferred from the
database schema. GRDB will complain with a fatal error such as Ambiguous
foreign key from book to person
, or Could not infer foreign key from book
to person
.
Your help is needed. You have to instruct GRDB which foreign key to use:
struct Book: TableRecord {
// Define foreign keys
static let authorForeignKey = ForeignKey(["authorId"]))
static let translatorForeignKey = ForeignKey(["translatorId"]))
// Use foreign keys to define associations:
static let author = belongsTo(Person.self, using: authorForeignKey)
static let translator = belongsTo(Person.self, using: translatorForeignKey)
}
Foreign keys are always defined from the table that contains the columns at the origin of the foreign key. Person’s symmetric HasMany associations reuse Book’s foreign keys:
struct Person: TableRecord {
static let writtenBooks = hasMany(Book.self, using: Book.authorForeignKey)
static let translatedBooks = hasMany(Book.self, using: Book.translatorForeignKey)
}
Foreign keys can also be defined from query interface columns:
struct Book: TableRecord {
enum Columns: String, ColumnExpression {
case id, title, authorId, translatorId
}
static let authorForeignKey = ForeignKey([Columns.authorId]))
static let translatorForeignKey = ForeignKey([Columns.translatorId]))
}
When the destination table of a foreign key does not define any primary key, you need to provide the full definition of a foreign key:
struct Book: TableRecord {
static let authorForeignKey = ForeignKey(["authorId"], to: ["id"]))
static let author = belongsTo(Person.self, using: authorForeignKey)
}
-
Creates a ForeignKey intended to define a record association.
struct Book: TableRecord { // Define foreign keys static let authorForeignKey = ForeignKey(["authorId"])) static let translatorForeignKey = ForeignKey(["translatorId"])) // Use foreign keys to define associations: static let author = belongsTo(Person.self, using: authorForeignKey) static let translator = belongsTo(Person.self, using: translatorForeignKey) }
Declaration
Swift
public init(_ originColumns: [String], to destinationColumns: [String]? = nil)
Parameters
originColumns
The columns at the origin of the foreign key.
destinationColumns
The columns at the destination of the foreign key. When nil (the default), GRDB automatically uses the primary key.
-
Creates a ForeignKey intended to define a record association.
struct Book: TableRecord { // Define columns enum Columns: String, ColumnExpression { case id, title, authorId, translatorId } // Define foreign keys static let authorForeignKey = ForeignKey([Columns.authorId])) static let translatorForeignKey = ForeignKey([Columns.translatorId])) // Use foreign keys to define associations: static let author = belongsTo(Person.self, using: authorForeignKey) static let translator = belongsTo(Person.self, using: translatorForeignKey) }
Declaration
Swift
public init(_ originColumns: [ColumnExpression], to destinationColumns: [ColumnExpression]? = nil)
Parameters
originColumns
The columns at the origin of the foreign key.
destinationColumns
The columns at the destination of the foreign key. When nil (the default), GRDB automatically uses the primary key.