2011-09-30 36 views
2

使用以下模型,我正在寻找一种高效且直接的方式来返回所有具有0个父任务(实质上是顶级任务)的任务。我最终还是希望返回0个子任务,所以一个通用的解决方案会很棒。这可能使用现有的DataMapper功能,或者我需要定义一个方法来手动过滤结果?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 

我希望能够在任务类似定义共享方法:

def self.without_parents 
    #Code to return collection here 
end 

谢谢!

回答

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之类的内容。

+0

谢谢。不是我希望的答案,但答案仍然=) – Joel