DataMapper按关联计数过滤记录

时间:2011-09-30 20:29:47

标签: ruby orm ruby-datamapper

使用以下模型,我正在寻找一种有效且直接的方法来返回所有具有0个父任务的任务(本质上是顶级任务)。我最终还想要返回0子任务之类的东西,所以一般的解决方案会很棒。这是否可以使用现有的DataMapper功能,或者我是否需要定义一种手动过滤结果的方法?

class Task
  include DataMapper::Resource

  property :id,    Serial
  property :name , String, :required => true

  #Any link of type parent where this task is the target, represents a parent of this task 
  has n, :links_to_parents, 'Task::Link', :child_key => [ :target_id ], :type => 'Parent'
  #Any link of type parent where this task is the source, represents a child of this task
  has n, :links_to_children, 'Task::Link', :child_key => [ :source_id ], :type => 'Parent'

  has n, :parents, self,
    :through => :links_to_parents,
    :via => :source

  has n, :children, self,
    :through => :links_to_children,
    :via => :target

  def add_parent(parent)
    parents.concat(Array(parent))
    save
    self
  end

  def add_child(child)
    children.concat(Array(child))
    save
    self
  end

  class Link
    include DataMapper::Resource

    storage_names[:default] = 'task_links'

    belongs_to :source, 'Task', :key => true
    belongs_to :target, 'Task', :key => true
    property :type, String
  end

end

我希望能够在Task类上定义一个共享方法,如:

def self.without_parents
   #Code to return collection here
end

谢谢!

1 个答案:

答案 0 :(得分:4)

DataMapper在这些场景中失败,因为你正在寻找的是LEFT JOIN查询,其中右边的所有内容都是NULL。

SELECT tasks.* FROM tasks LEFT JOIN parents_tasks ON parents_tasks.task_id = task.id WHERE parents_tasks.task_id IS NULL

你父母/孩子的情况在这里没有什么不同,因为它们都是n:n映射。

单独使用DataMapper(至少在版本1.x中)获得的效率最高的是:

Task.all(:parents => nil)

将执行两个查询。第一个是来自n:n数据透视表(WHERE task_id NOT NULL)的相对简单的SELECT,第二个是第一个查询中返回的所有id的巨大NOT IN ...最终不是你在寻找什么。

我认为你不得不自己编写SQL;)

编辑| https://github.com/datamapper/dm-ar-finders并且它的find_by_sql方法可能很有用。如果字段名称抽象对您很重要,您可以在SQL中引用Model.storage_nameModel.some_property.field等内容。