如何在DataMapper中为同一个模型建立两个多对多关系?

时间:2011-06-23 22:15:23

标签: ruby many-to-many datamapper

修改:根据评论中的建议更新了问题以显示我对:child_key => [:comparison_id]的使用情况。

我有两个看起来像这样的模型:

class Comparison
  include DataMapper::Resource
  property :id, Serial
end

class Msrun
  include DataMapper::Resource
  property :id, Serial
  property :name, String
end

比较来自比较两组Msruns。我以为我会通过Comparison和Msrun之间的两个多对多关系代表这一点,但是我在如何在DataMapper中做到这一点时,我正在打击我的脑袋。我知道通过添加以下内容可以获得多对多关系:

has n, :whatevers, :through => Resource

然而,这只会在两个模型之间建立一对多的关系。我还尝试创建两个连接模型并手动指定关系,并为每个关系手动指定子键,如下所示:

# Join model for the comparison-msrun many-to-many relationship.
class First
  include DataMapper::Resource
  belongs_to :msrun, :key => true
  belongs_to :comparison, :key => true
end


# Join model for the comparison-msrun many-to-many relationship.
class Second
  include DataMapper::Resource
  belongs_to :msrun, :key => true
  belongs_to :comparison, :key => true
end

class Comparison
  include DataMapper::Resource
  property :id, Serial

  has n, :firsts
  has n, :msrun_firsts, 'Msrun', :through => :firsts, :child_key => [:msrun_id]

  has n, :seconds
  has n, :msruns_seconds, 'Msrun', :through => :seconds, :child_key => [:msrun_id]
end

class Msrun
  include DataMapper::Resource
  property :id, Serial
  property :name, String

  has n, :firsts
  has n, :comparison_firsts, 'Comparison', :through => :firsts, :child_key => [:comparison_id]

  has n, :seconds
  has n, :comparison_seconds, 'Comparison', :through => :seconds, :child_key => [:comparison_id]
end

运行automigrate会导致以下错误:

rake aborted!
No relationships named msrun_firsts or msrun_first in First

我在这里做错了什么?我怎样才能做到这一点?

2 个答案:

答案 0 :(得分:0)

根据DataMapper docs

我相信你可以做到:

class Msrun
    include DataMapper::Resource
    property :id, Serial
    property :name, String

    has n, :firsts #This line could probably be omitted 
    has n, :first_comparisons, 'Comparison', :through => :firsts

    has n, :seconds #This line could probably be omitted 
    has n, :second_comparisons, 'Comparison', :through => :seconds
end

答案 1 :(得分:0)

您所观察到的是,关系存储在一个类似于对象的集合中,更具体地说,是一个使用关系名称作为鉴别器的集合。那么在你的情况下会发生的是,后一个定义会覆盖前者,因为集合不允许重复的条目(在我们的例子中,为了集合的目的,用较新的条目替换较旧的条目,相同的条目)。

这有实际的原因。在一个模型上声明两个所谓的不同关系是没有意义的,但是将它们命名为相同。在尝试访问它们时,您如何区分它们?这体现在DM的实现中,其中由关系名称命名的方法在Resource上定义。因此,在您尝试向集合添加副本的情况下,DM最终会做的是,它将仅使用后面的选项来生成该方法的实现。即使它接受重复的关系名称,后一种关系也会导致相同方法的覆盖/重新定义版本,从而使您具有相同的净效果。

因此,您需要在模型上定义不同名称的关系。当你考虑它时,它真的很有意义。为了帮助DM推断要使用的模型,您可以将模型名称(或常量本身)作为第3个参数传递给has方法,或者作为belongs_to

的第2个参数传递
class Comparison
  include DataMapper::Resource
  property :id, Serial

  has n, :firsts
  has n, :first_msruns, 'Msrun', :through => :firsts

  has n, :seconds
  has n, :second_msruns, 'Msrun', :through => :seconds
end

class Msrun
  include DataMapper::Resource
  property :id, Serial
  property :name, String

  has n, :firsts
  has n, :first_comparisons, 'Comparison', :through => :firsts

  has n, :seconds
  has n, :second_comparisons, 'Comparison', :through => :seconds

end

希望有所帮助!