Rails:这是单一 Table 继承 (STI) 的用例吗?
Rails: Is this a use case for Single Table Inheritance (STI)?
考虑一下这个设置。请理解我们的设置更加详细,但这是一个简单的示例。
competition
其中有 name
。这是一年一度的比赛。
competition_instances
其中有 location
, starts_at
.
每个比赛有 sports
其中有 name
.
示例:
competition
.name
: "Super Bowl" 每年都有不同的 competition_instances
但 sport
保持不变。
反之,competition
.name
:"Olympics"在每个competition_instance
中有不同的competition_instances
和不同的sports
。
是否最好创建 competition_sports
和 competition_instance_sports
并将 competition_instance_sports
作为 competition_sports
的子类?
GOAL: 如果存在 competition_instance_sports
记录,则使用 competition_sports
记录。在我们真实世界的应用程序中,每个 competition/competition_instance 可以有 20-50 条运动记录。我们怎样才能最好地实现?
根据我对问题的理解,我看不出 STI 在这种情况下有什么帮助。但是加入 table 会让你到达你想要的地方。
我建议创建一个新的 table sports
,这个模型将包含每项运动的所有具体细节。 competition_instance.rb
将有 one/many sport.rb
。 competiton.rb
将有许多 sports
到 competition_instance.rb
。
competition.rb
Class Competition < ActiveRecord::Base
has_many :competition_instances
has_many :sports, through: :competition_instances
end
competition_instance.rb
Class CompetitionInstance < ActiveRecord::Base
belongs_to :competition
belongs_to :sport
end
sport.rb
Class Sport < ActiveRecord::Base
has_many :competition_instances
end
通过使用此设计,您将能够实现以下目标:
1- 您将在数据库中拥有预定义的运动及其特定属性。
2-每场比赛都会有.sports
这会给本次比赛的所有运动项目提供奥运案例。
3- 您将能够在比赛实例 table.
中为每个比赛实例(例如 event_start_time
和 event_end_time
)设置特定属性
这不是单个 table 继承的情况,因为 competition_instance
不能替代 competition
并且 1 个 competition
可以有多个 competition_instances
.所以你有 3 tables:
competitions
sports
competition_instances
competition_instances
有一个 competitions
的外键,因为 1 competition
可以有很多 competition_instances
但每个 competition_instance
有一个 competition
.
是否将 sports
附加到 competitions
或 competition_instances
取决于您的用例的具体限制。我不完全明白你所说的 "each competition/competition_instance
can have 20-50 sport
records" 是什么意思。我希望每个 competition_instance
恰好有一个 sport
,所以您可以保留它,或者您也可以将 sports
的集合附加到 competition
,所以您可以在 competition_instance
之前通过 sport
检索新的 competitions
。我需要有关您的用例的更多详细信息,以便为您提供进一步的建议。
我只是在考虑这样一种情况,即有标准的项目总是在奥运会上,也有一些是增加的,比如主办国提出的项目。
我会用Polymorphic Associations, in a "reverse manner".
class Competition < ActiveRecord::Base
has_many :competition_instances
has_many :competition_sports, as: :event
end
class CompetitionInstance < ActiveRecord::Base
belongs_to :competition
has_many :competition_sports, as: :event
def events_array # neater by sacrificing ActiveRecord methods
competition.competition_sports + competition_sports
end
def events # messier, returns ActiveRecord relationship
CompetitionSport.where( " ( event_id = ? AND event_type = 'Competition' ) OR
( event_id = ? AND event_type = 'CompetitionInstance')", competition_id, id )
end
end
class Sport < ActiveRecord::Base
has_many :events, as: :competition_sport
end
class CompetitionSport < ActiveRecord::Base
belongs_to :sport
belongs_to :event, polymorphic: true
end
这允许:
competition.competition_sports # standard sports
competition_instance.competition_sports # only those specific for this instance
competition_instance.events # includes sports from both
针对 "Is this a use case for STI" 的原始问题,如果不了解您的环境的全部复杂性,很难说这是不是。但这里有一些需要考虑的事项:
节选自How (and When) to Use Single Table Inheritance in Rails - eugenius blog:
STI should be considered when dealing with model classes that share much of the same functionality and data fields, but you want more granular control over extending or adding to each class individually. Rather than duplicate code or forego the individual functionalities, STI permits you to use keep your data in a single table while writing specialized functionality.
你已经简化了你的例子,但听起来 competition
和 competition_instance
本质上不是同一个对象,只有细微的行为差异。根据您的描述,我可能会将这些对象重命名为 event
和 competition
,或者在说明这些对象实际代表什么方面对您来说更有意义的名称。我认为 'The Olympics' 是一项通用赛事,而“100 米短跑”是奥运会上举办的一项比赛。或者 "The SuperBowl" 2014 年只举办了一场比赛,"SuperBowl XLIX".
您还用 database-normalization
标记了这个问题,STI 对此无济于事。如果您的共享对象之间的属性略有不同,您最终会到处都是空字段。
我建议您参考此处的其他答案,了解您应该如何设置这些对象以使其按预期运行。
考虑一下这个设置。请理解我们的设置更加详细,但这是一个简单的示例。
competition
其中有 name
。这是一年一度的比赛。
competition_instances
其中有 location
, starts_at
.
每个比赛有 sports
其中有 name
.
示例:
competition
.name
: "Super Bowl" 每年都有不同的 competition_instances
但 sport
保持不变。
反之,competition
.name
:"Olympics"在每个competition_instance
中有不同的competition_instances
和不同的sports
。
是否最好创建 competition_sports
和 competition_instance_sports
并将 competition_instance_sports
作为 competition_sports
的子类?
GOAL: 如果存在 competition_instance_sports
记录,则使用 competition_sports
记录。在我们真实世界的应用程序中,每个 competition/competition_instance 可以有 20-50 条运动记录。我们怎样才能最好地实现?
根据我对问题的理解,我看不出 STI 在这种情况下有什么帮助。但是加入 table 会让你到达你想要的地方。
我建议创建一个新的 table sports
,这个模型将包含每项运动的所有具体细节。 competition_instance.rb
将有 one/many sport.rb
。 competiton.rb
将有许多 sports
到 competition_instance.rb
。
competition.rb
Class Competition < ActiveRecord::Base
has_many :competition_instances
has_many :sports, through: :competition_instances
end
competition_instance.rb
Class CompetitionInstance < ActiveRecord::Base
belongs_to :competition
belongs_to :sport
end
sport.rb
Class Sport < ActiveRecord::Base
has_many :competition_instances
end
通过使用此设计,您将能够实现以下目标:
1- 您将在数据库中拥有预定义的运动及其特定属性。
2-每场比赛都会有.sports
这会给本次比赛的所有运动项目提供奥运案例。
3- 您将能够在比赛实例 table.
中为每个比赛实例(例如event_start_time
和 event_end_time
)设置特定属性
这不是单个 table 继承的情况,因为 competition_instance
不能替代 competition
并且 1 个 competition
可以有多个 competition_instances
.所以你有 3 tables:
competitions
sports
competition_instances
competition_instances
有一个 competitions
的外键,因为 1 competition
可以有很多 competition_instances
但每个 competition_instance
有一个 competition
.
是否将 sports
附加到 competitions
或 competition_instances
取决于您的用例的具体限制。我不完全明白你所说的 "each competition/competition_instance
can have 20-50 sport
records" 是什么意思。我希望每个 competition_instance
恰好有一个 sport
,所以您可以保留它,或者您也可以将 sports
的集合附加到 competition
,所以您可以在 competition_instance
之前通过 sport
检索新的 competitions
。我需要有关您的用例的更多详细信息,以便为您提供进一步的建议。
我只是在考虑这样一种情况,即有标准的项目总是在奥运会上,也有一些是增加的,比如主办国提出的项目。
我会用Polymorphic Associations, in a "reverse manner".
class Competition < ActiveRecord::Base
has_many :competition_instances
has_many :competition_sports, as: :event
end
class CompetitionInstance < ActiveRecord::Base
belongs_to :competition
has_many :competition_sports, as: :event
def events_array # neater by sacrificing ActiveRecord methods
competition.competition_sports + competition_sports
end
def events # messier, returns ActiveRecord relationship
CompetitionSport.where( " ( event_id = ? AND event_type = 'Competition' ) OR
( event_id = ? AND event_type = 'CompetitionInstance')", competition_id, id )
end
end
class Sport < ActiveRecord::Base
has_many :events, as: :competition_sport
end
class CompetitionSport < ActiveRecord::Base
belongs_to :sport
belongs_to :event, polymorphic: true
end
这允许:
competition.competition_sports # standard sports
competition_instance.competition_sports # only those specific for this instance
competition_instance.events # includes sports from both
针对 "Is this a use case for STI" 的原始问题,如果不了解您的环境的全部复杂性,很难说这是不是。但这里有一些需要考虑的事项:
节选自How (and When) to Use Single Table Inheritance in Rails - eugenius blog:
STI should be considered when dealing with model classes that share much of the same functionality and data fields, but you want more granular control over extending or adding to each class individually. Rather than duplicate code or forego the individual functionalities, STI permits you to use keep your data in a single table while writing specialized functionality.
你已经简化了你的例子,但听起来 competition
和 competition_instance
本质上不是同一个对象,只有细微的行为差异。根据您的描述,我可能会将这些对象重命名为 event
和 competition
,或者在说明这些对象实际代表什么方面对您来说更有意义的名称。我认为 'The Olympics' 是一项通用赛事,而“100 米短跑”是奥运会上举办的一项比赛。或者 "The SuperBowl" 2014 年只举办了一场比赛,"SuperBowl XLIX".
您还用 database-normalization
标记了这个问题,STI 对此无济于事。如果您的共享对象之间的属性略有不同,您最终会到处都是空字段。
我建议您参考此处的其他答案,了解您应该如何设置这些对象以使其按预期运行。