我有一个案例,其中一个模型与另外两个模型相关。我正在尝试正确设置这3个模型之间的模型关系。
简化示例...前两个表格为clients
和invoices
:
db.create_table(:clients) do
primary_key :id
String :name
end
db.create_table(:invoices) do
primary_key :id
String :description
Integer :balance
end
第三个表名为files
,包含可与clients
或invoices
相关的文件记录:
db.create_table(:files) do
primary_key :id
String :name
String :path
String :type # [image, pdf, word, excel]
end
有2个连接表可以将files
连接到clients
和invoices
:
db.create_table(:clients_files) do
Integer :client_id
Integer :file_id
end
db.create_table(:files_invoices) do
Integer :invoice_id
Integer :file_id
end
问题是,如何正确设置模型中的关系,以便每个client
和invoice
可以有一个或多个相关的files
?
我可以使用many_to_many
和has_many :through
关联完成此操作,但是,这似乎不是正确的方法,因为给定的file
可以仅属于一个customer
或invoice
,而不属于多个。
我也可以使用多态,但documentation discourages this approach:
Sequel不鼓励使用多态关联,即 默认情况下不支持它们的原因。所有多态关联 可以通过使用附加表和/或列使其成为非多态的 而不是将包含关联类名的列作为 字符串。
多态关联破坏了参照完整性 比非多态关联明显更复杂,所以他们的 除非您坚持使用现有设计,否则不建议使用 使用它们。
更正确的关联是one_to_many_through
或many_to_one_through
,但我找不到正确的方法来执行此操作。是否有一种香草的Sequel方法来实现这一目标,还是有一个提供此功能的模型插件?
答案 0 :(得分:0)
使用您当前的架构,您只想对文件使用many_to_many关联:
title
要确保每个文件只能有一个客户端/发票,您可以将file_id作为clients_files和files_invoices的主键(一个普通的唯一约束/索引也可以)。然后你可以使用one_through_one:
INDEX(title, emp_no)
请注意,这仍然允许将文件与客户端和发票相关联。如果要防止这种情况,则需要更改架构。您可以将client_id和invoice_id外键移动到files表(或使用带有两个键的单个连接表),并使用检查约束来检查是否只设置了其中一个。
请注意,避免多态键(除了复杂性)的主要原因是它允许数据库强制引用完整性。使用当前的连接表,您不会创建外键,只是整数字段,因此您不会强制执行参照完整性。