使用以下模型,我正在寻找一种有效且直接的方法来返回所有具有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
谢谢!
答案 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_name
和Model.some_property.field
等内容。