DataMapper фильтрует записи по количеству ассоциаций - PullRequest
2 голосов
/ 01 октября 2011

В следующей модели я ищу эффективный и простой способ вернуть все Задачи, которые имеют 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 Ответ

4 голосов
/ 01 октября 2011

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)

Который выполнит два запроса. Первый - это относительно простой SELECT из сводной таблицы n: n (WHERE task_id NOT NULL), а второй - гигантский NOT IN для всех идентификаторов, возвращаемых в первом запросе ... что в конечном итоге не то, что вы ищу.

Я думаю, вам, к сожалению, придется самостоятельно писать SQL;)

РЕДАКТИРОВАТЬ | https://github.com/datamapper/dm-ar-finders и его метод find_by_sql может представлять интерес. Если абстракция имени поля важна для вас, вы можете ссылаться на такие вещи, как Model.storage_name и Model.some_property.field в вашем SQL.

...