2

次のモデルを使用して、親タスクが 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

ありがとう!

4

1 に答える 1

4

DataMapper は、これらのシナリオでは機能しません。実際に探しているのは、右側のすべてが NULL である LEFT JOIN クエリだからです。

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

どちらも n:n マッピングであるため、親と子の状況はここで違いはありません。

(少なくともバージョン 1.x では) DataMapper だけで得られる最も効率的な方法は次のとおりです。

Task.all(:parents => nil)

これにより、2 つのクエリが実行されます。1 つ目は n:n ピボット テーブル ( WHERE task_id NOT NULL) からの比較的単純な SELECT であり、2 つ目は最初のクエリで返されたすべての ID に対して巨大なNOT INものです...これは最終的に探しているものではありません。

残念ながら、自分で SQL を書かなければならないと思います ;)

編集 | https://github.com/datamapper/dm-ar-findersとその find_by_sql メソッドが興味深いかもしれません。フィールド名の抽象化が重要な場合は、SQL で や などを参照できModel.storage_nameますModel.some_property.field

于 2011-10-01T01:10:14.430 に答える