使用ruby和datamapper检索具有多对多关联的记录

我正在学习Sinatra,我已经阅读了datamapper文档并找到了这个n到n的关系示例:

class Photo include DataMapper::Resource property :id, Serial has n, :taggings has n, :tags, :through => :taggings end class Tag include DataMapper::Resource property :id, Serial has n, :taggings has n, :photos, :through => :taggings end class Tagging include DataMapper::Resource belongs_to :tag, :key => true belongs_to :photo, :key => true end 

我从上面的代码中理解的是,一张照片可能有很多或零标签,而标签可能有很多或零照片。 如何检索已加载相关标签的照片列表。 我知道datamapper使用惰性方法,因此它不会自动加载关联的类(在本例中为photo.tag)。 所以这:

 photos = Photo.all 

会导致一个没有标签的Photo对象的数组。 有没有办法自动检索它,还是我必须迭代数组并手动设置?

提前致谢!

我也有一个类似关系的数据库。 AuthorPostTag是主要模型, Subscribedtag TaggingTagging是通过has n, :through构建的。

 class Author include DataMapper::Resource property :id, Serial property :email, String, :unique => true property :password, String property :first_name, String property :last_name, String property :bio, Text property :phone, String, :unique => true property :twitter, String, :unique => true property :facebook, String, :unique => true property :show_phone, Boolean, :default => false property :show_facebook, Boolean, :default => false property :show_twitter, Boolean, :default => false property :is_admin, Boolean, :default => false property :this_login, DateTime property :last_login, DateTime property :session_lasting, Integer, :default => 0 has n, :posts has n, :subscribedtags has n, :tags, :through => :subscribedtags end class Post include DataMapper::Resource property :id, Serial property :title, String, :required => true property :body, Text, :required => true property :is_blog_post, Boolean, :default => true property :viewed, Integer, :default => 0 property :featured, Boolean, :default => false property :created_at, DateTime property :updated_at, DateTime belongs_to :author belongs_to :category has n, :comments has n, :taggings has n, :tags, :through => :taggings validates_length_of :title, :min => 3 validates_length_of :body, :min => 20 validates_format_of :title, :with => /\w/ #some other methods end class Tag include DataMapper::Resource property :id, Serial property :name, String, :unique => true has n, :taggings has n, :posts, :through => :taggings has n, :subscribedtags has n, :authors, :through => :subscribedtags validates_length_of :name, :min => 1 validates_format_of :name, :with => /\w/ # some other methods end class Tagging include DataMapper::Resource belongs_to :tag, :key => true belongs_to :post, :key => true end class Subscribedtag include DataMapper::Resource belongs_to :tag, :key => true belongs_to :author, :key => true end 

您定义模型的方式允许您编写类似的查询。

 2.2.0 :016 > kant = Tag.get(25) # getting tag instance with id 25 and assign it to variable named kant => # 2.2.0 :017 > kant.posts => #returns post instances which has this tag. 2.2.0 :018 > kant.posts.count # count of posts with this tag. => 2 2.2.0 :021 > kant.posts.first.author.first_name => "Ziya" # check my author class and first_name attribute. 

假设我想要检索没有post的标签实例。 一个简单的ruby命令。

 2.2.0 :024 > Tag.each {|tnp| puts tnp.name if tnp.posts.count == 0} Latın Python Ruby Sosializm Hegel 

或者根据post检索标签。

 2.2.0 :034 > p = Post.get(9) => # @is_blog_post=false @viewed=0 @featured=false @created_at=# @updated_at=# @author_id=1 @category_id=1> 2.2.0 :035 > p.tags => [#] 

检索没有标签的post。

 2.2.0 :043 > Post.each {|pnt| puts pnt.id if pnt.tags.count.zero?} 8 #post with id has no tags 2.2.0 :044 > Post.get(8).tags.count => 0 

您还可以通过其他属性进行查询。

 2.2.0 :046 > Tag.first(:name => "Lorem").id => 30 

迭代结果

 2.2.0 :050 > Tag.first(:name => "Lorem").posts.each {|lorempost| puts lorempost.title} # printing post titles which are tagged with lorem. Get'em all qwerty 

我还通过Subscribedtags模型将作者与标签相关联,我可以轻松地检查哪个作者订阅了哪个标签,反之亦然。

 2.2.0 :055 > z = Author.get(1) => # returns details of author instance 2.2.0 :056 > z.tags 

=> [#,#,#,#]

或通过Subscritag查询

 2.2.0 :057 > z.subscribedtags => [#, #, #, #] 

您还可以定义自己的function以利用查询。 我已经定义了一个subscribed_tags方法,它返回一个订阅标签名称的数组。

 2.2.0 :058 > z.subscribed_tags => ["Həyat", "Məstan", "İmmanuil Kant", "Lorem"] 

如果我想检索随机作者的first_name属性,谁订阅了名为“Lorem”的标签,

 2.2.0 :062 > Tag.first(:name => "Lorem").authors.sample.first_name => "Ziya" 

作为第二个问题的答案,是的,大多数时候你必须迭代。

因为Photos.all返回Photo对象实例的集合。 并且此实例单独具有标记属性,而不是数组由Photo实例组成。

如果你打电话给p = Photo.all; print p.tags; p = Photo.all; print p.tags; 它将返回与所有照片相关联的所有标签,这些标签可能是您想要的,也可能不是。

如果这些还不够,请随意提出更多问题。