我应该如何使用一个外键引用两个表?
How should I reference two tables with a single foreign key?
我有一个公司模型和一个客户模型。两者可以是关系
type Customer struct {
gorm.Model
Title string
}
type Company struct {
gorm.Model
Title string
}
type Relation struct {
gorm.Model
CustomerOrCompanyID uint
}
所以两者是一种关系。我怎样才能让我的关系指向公司或客户?
注:从纯粹的SQL角度来说,因为我还没有与gorm
合作过:
在我上面的评论中我问:
How would you know if the ID in CustomerOrCompanyID
is a customer ID or a company ID? Do you have some boolean field saying this is a customer or not? Or does the ID itself contain that information? Like cust-1234
and comp-1234
?
既然你需要一种方法来区分CustomerOrCompanyID
中的ID类型,我建议有两个字段:CustomerID
和CompanyID
。其中之一总是 0
(或 NULL
)。
这样你就知道要加入哪个 table 并且也可以同时加入两者,具体取决于每行的数据类型,客户或公司的列将被填充。
我认为如果有 2 个字段,gorm
应该不会再有问题,因为它会将每个字段作为一个正常关系来处理,而不是为所有列设置。
一些示例 SQL 语句 (MySQL Dialekt):
所有客户:
SELECT
Relation.ID as RelID, Relation.OtherColumn,
Customer.ID, Customer.Name
/* etc. */
FROM
Relation INNER JOIN Customer ON (Relation.CustomerID=Customer.ID);
所有公司:
SELECT
Relation.ID as RelID, Relation.OtherColumn,
Company.ID, Company.Name
/* etc. */
FROM
Relation INNER JOIN Company ON (Relation.CompanyID=Company.ID);
您可能还需要 Relation
中包含公司和客户列的所有数据,并在前端决定使用哪些数据:
SELECT
Relation.ID as RelID,
Relation.OtherColumn,
Customer.ID as CustID,
Customer.Name as CustName,
Company.ID as CompID,
Company.Name as CompName,
/* etc. */
FROM
Relation
LEFT JOIN Company ON (Relation.CompanyID=Company.ID)
LEFT JOIN Customer ON (Relation.CustomerID=Customer.ID);
在 Gorm 中有一种方法可以使用多态的 Has One 关系自然地做到这一点。这将使您能够轻松 运行 @TheSphinX 提供的一些查询。
但是,您需要向关系 table 添加类型鉴别器列才能使其正常工作:
type Customer struct {
gorm.Model
Title string
Rel Relation `gorm:"polymorphic:Owner"`
}
type Company struct {
gorm.Model
Title string
Rel Relation `gorm:"polymorphic:Owner"`
}
type Relation struct {
gorm.Model
Foo string
OwnerID uint
OwnerType string
}
现在您可以正常创建记录了:
cust := Customer{
Title: "Cust",
Rel: Relation{Foo: "bar"},
}
comp := Company{
Title: "Comp",
Rel: Relation{Foo: "baz"},
}
db.Create(&cust)
db.Create(&comp)
要运行一个获取客户或公司相关信息的查询,就像@TehSphinX 的前两个查询一样,你会做这样的事情:
var cust Customer
db.Joins("Rel").First(&cust, 1)
最后一个查询会更复杂,但也可以使用自定义行结构和连接来完成:
var rows []struct {
Relation
Customer Customer `gorm:"embedded;embeddedPrefix:cust_"`
Company Company `gorm:"embedded;embeddedPrefix:comp_"`
}
db.Select(`
relations.*,
customers.id AS cust_id,
customers.title AS cust_title,
companies.id AS comp_id,
companies.title AS comp_title
`).
Model(&Relation{}).
Joins("LEFT JOIN customers ON relations.owner_id = customers.id AND relations.owner_type = 'customers'").
Joins("LEFT JOIN companies ON relations.owner_id = companies.id AND relations.owner_type = 'companies'").
Find(&rows)
// now rows[i].Relation is filled, and rows[i].Customer or rows[i].Company
// are non-zero depending on rows[i].Relation.OwnerType
我有一个公司模型和一个客户模型。两者可以是关系
type Customer struct {
gorm.Model
Title string
}
type Company struct {
gorm.Model
Title string
}
type Relation struct {
gorm.Model
CustomerOrCompanyID uint
}
所以两者是一种关系。我怎样才能让我的关系指向公司或客户?
注:从纯粹的SQL角度来说,因为我还没有与gorm
合作过:
在我上面的评论中我问:
How would you know if the ID in
CustomerOrCompanyID
is a customer ID or a company ID? Do you have some boolean field saying this is a customer or not? Or does the ID itself contain that information? Likecust-1234
andcomp-1234
?
既然你需要一种方法来区分CustomerOrCompanyID
中的ID类型,我建议有两个字段:CustomerID
和CompanyID
。其中之一总是 0
(或 NULL
)。
这样你就知道要加入哪个 table 并且也可以同时加入两者,具体取决于每行的数据类型,客户或公司的列将被填充。
我认为如果有 2 个字段,gorm
应该不会再有问题,因为它会将每个字段作为一个正常关系来处理,而不是为所有列设置。
一些示例 SQL 语句 (MySQL Dialekt):
所有客户:
SELECT
Relation.ID as RelID, Relation.OtherColumn,
Customer.ID, Customer.Name
/* etc. */
FROM
Relation INNER JOIN Customer ON (Relation.CustomerID=Customer.ID);
所有公司:
SELECT
Relation.ID as RelID, Relation.OtherColumn,
Company.ID, Company.Name
/* etc. */
FROM
Relation INNER JOIN Company ON (Relation.CompanyID=Company.ID);
您可能还需要 Relation
中包含公司和客户列的所有数据,并在前端决定使用哪些数据:
SELECT
Relation.ID as RelID,
Relation.OtherColumn,
Customer.ID as CustID,
Customer.Name as CustName,
Company.ID as CompID,
Company.Name as CompName,
/* etc. */
FROM
Relation
LEFT JOIN Company ON (Relation.CompanyID=Company.ID)
LEFT JOIN Customer ON (Relation.CustomerID=Customer.ID);
在 Gorm 中有一种方法可以使用多态的 Has One 关系自然地做到这一点。这将使您能够轻松 运行 @TheSphinX 提供的一些查询。
但是,您需要向关系 table 添加类型鉴别器列才能使其正常工作:
type Customer struct {
gorm.Model
Title string
Rel Relation `gorm:"polymorphic:Owner"`
}
type Company struct {
gorm.Model
Title string
Rel Relation `gorm:"polymorphic:Owner"`
}
type Relation struct {
gorm.Model
Foo string
OwnerID uint
OwnerType string
}
现在您可以正常创建记录了:
cust := Customer{
Title: "Cust",
Rel: Relation{Foo: "bar"},
}
comp := Company{
Title: "Comp",
Rel: Relation{Foo: "baz"},
}
db.Create(&cust)
db.Create(&comp)
要运行一个获取客户或公司相关信息的查询,就像@TehSphinX 的前两个查询一样,你会做这样的事情:
var cust Customer
db.Joins("Rel").First(&cust, 1)
最后一个查询会更复杂,但也可以使用自定义行结构和连接来完成:
var rows []struct {
Relation
Customer Customer `gorm:"embedded;embeddedPrefix:cust_"`
Company Company `gorm:"embedded;embeddedPrefix:comp_"`
}
db.Select(`
relations.*,
customers.id AS cust_id,
customers.title AS cust_title,
companies.id AS comp_id,
companies.title AS comp_title
`).
Model(&Relation{}).
Joins("LEFT JOIN customers ON relations.owner_id = customers.id AND relations.owner_type = 'customers'").
Joins("LEFT JOIN companies ON relations.owner_id = companies.id AND relations.owner_type = 'companies'").
Find(&rows)
// now rows[i].Relation is filled, and rows[i].Customer or rows[i].Company
// are non-zero depending on rows[i].Relation.OwnerType