我很难用使用Datamapper来模拟自引用,多对多,对称的实体:
我想跟踪我正在跟踪的各种软件版本的兼容性:
class SoftwareRelease
include DataMapper::Resource
property :id, Serial
property :software_release_type_id, Integer
property :version, String
belongs_to :software_release_type
has n, :compatibilities, child_key: [ :source_id ]
has n, :compatible_releases, self, through: :compatibilities, via: :target
end
class SoftwareReleaseType
include DataMapper::Resource
property :id, Serial
property :name, String
property :short_name, String
has n, :software_releases
end
class Compatibility
include DataMapper::Resource
belongs_to :source, 'SoftwareRelease', key: true
belongs_to :target, 'SoftwareRelease', key: true
end
给定的软件版本'a.b.c'可以有一种'hardware platfrom foo',而给定的软件版本'd.e.f'可以有一种'硬件平台栏'。
要在上面的代码中建立软件版本之间的兼容性,我必须执行2次添加
release_a_b_c.compatible_releases << release_d_e_f
release_d_e_f.compatible_releases << release_a_b_c
那有点难看。
我希望能够只做一次添加并建立对称关系。我显然可以在SoftwareRelease
中使用实例方法进行2次推送,但这感觉就像是在地毯下扫除丑陋。是否有优雅解决方案的想法?
很有责任,
的Pawel
PS
很久以前,活跃记录有acts_as_network插件,它做了类似的事情。在DM世界中找不到任何东西。
答案 0 :(得分:0)
我认为DM或其任何插件中没有任何东西可以做你想要的东西,但我想假设写一个实例方法来创建单向关系实际上相当优雅而且我不会不要认为它“彻底扫除地毯下的丑陋”。
在类中实现对象关系的部分功能是程序员可以通过在类中创建实例方法以有意义的方式扩展这些类。您需要对象之间的对称关系,因此编写这个简单的实例方法是有意义的并且是自我记录的。并且不存在副作用或不适当呼叫的风险,因为它是该特定类的公共方法。
我在这里并没有说任何新的东西,但我认为你的解决方案是完全可以接受的。坦率地说,我宁愿看到相对罕见的用例被推入程序员的域,而不是混乱DataMapper代码。我不需要那些大胖胖的Victorinox小刀,其中包括各种可以想象的工具。 :)