Как использовать Doctrine для хранения нескольких деревьев в одной таблице? - PullRequest
1 голос
/ 21 июня 2011

Я планирую использовать функцию вложенного набора, предусмотренную доктриной orm, для создания многопоточных комментариев.Другими словами, я хочу, чтобы в одной таблице хранилось несколько независимых деревьев.В моем конкретном случае была бы какая-то сущность "новости", имеющая множество "комментариев".

News:
  columns:
    content: clob

Comment:
  actAs:
    NestedSet:
      hasManyRoots: true
      rootColumnName: root_id
 columns:
    benutzer_id:       { type: integer, notnull: true }
    ref_id:            { type: integer, notnull: true }
    content:            { type: clob, notnull: true}
  relations:
    News:
      class: News
      local: ref_id
      foreign: id

Как мне указать доктрине использовать comment.ref_id в качестве столбца дискриминатора?Таким образом, в результате только узлы, имеющие одинаковый ref_id, относятся к одному дереву.В настоящее время все древовидные операции влияют на все узлы, хранящиеся в таблице комментариев.Желательно, чтобы только узлы с данным именем столбца ("ref_id") действовали как одно отдельное дерево.

update Для решения проблемы я думал о том, чтобы создать способ иметь многоhasManyRoots-деревья в одной таблице.Чтобы загрузить дерево, нужно создать дерево следующим образом:

$category->$treeObject = Doctrine_Core::getTable('Category')->getTree('ref_id',12);

Все действия по манипулированию деревом должны включать «WHERE ref_id = 12 AND ...».В моем случае вы бы манипулировали деревом комментариев для новостей №12.Таким образом, операторы обновления базы данных будут меньше.Поскольку ref_id относится к новостям, уже существует индекс ref_id, поэтому он должен работать довольно быстро.

окончательное решение - НЕ ЧАСТЬ ВОПРОСА

через многоеОбсуждая и спя, я придумал следующую схему.это включает сокращение столбцов в таблице комментариев (исключено ref_id, root_id теперь ссылается на корневой комментарий, а не на новости).

News:
  columns:
    content: clob
    comment_root_id:      { type: integer, notnull: false }
  relations:
    CommentRoot:
      class: Comment
      local: comment_root_id
      type: one

Comment:
  actAs:
    NestedSet:
      hasManyRoots: true
  columns:
    content:            { type: clob, notnull: true}

Я думаю, что это более чисто в этом смысле.Создание новостей требует создания фиктивного корневого узла.

        $treeObject = Doctrine_Core::getTable('Comment')->getTree();

        $root = new Comment();
        $root ->content = 'root';
        $root->save();
        $root = $treeObject->createRoot($root);

        $news->setCommentRoot($root);
        $news->save();

И, наконец, вы можете использовать левое объединение при запросе "Новости", чтобы получить корневой комментарий, чтобы сообщить вам, сколько детей существует.

Для проблем производительности вы можете вручную поместить индекс в столбец root_id.Готово.

1 Ответ

2 голосов
/ 21 июня 2011

значение для rootColumnName является дескриптором, поэтому, если вы хотите использовать ref id, вы должны сделать:

  actAs:
    NestedSet:
      hasManyRoots: true
      rootColumnName: ref_id

UPDATE:

Для решения этой проблемы я думал о том, как создать множество таблиц hasManyRoots в одной таблице.

Вы пытаетесь переделать дополнительный функционал! :-)

Вызов getTree на самом деле не выполняет запрос ... он просто возвращает экземпляр реализации - Doctrine_Tree_NestedSet. У вас есть шанс на то, что вы хотите, прежде чем запросить ...

Чтобы просто получить определенное дерево:

$category->$treeObject = Doctrine_Core::getTable('Category')->getTree()->fetchTree(array('root_id' => 12));

Первый аргумент fetchTree - это массив опций, которые вы можете указать здесь, включая

  • root_id (будет преобразовано в то, что вы указали в качестве опции root_id в своей схеме)
  • глубина для извлечения как depth

Кроме того, если вам нужны более сложные опции, чем вы можете предоставить базовый запрос, прежде чем вы получите дерево, которое имеет любые критерии запроса, которые вы хотите:

// join you news item
$q = Doctrine_Core::getTable('Category')->create('c')
  ->leftJoin('c.News n with n.id = ?', $articleId);

$tree = Doctrine_Core::getTable('Category')->getTree();
$tree->setBaseQuery($q);
$nodes = $tree->fetchTree(array('root_id' => 12));

root_id дерева всегда должен указывать на другой узел дерева ... а не на что-то внешнее. Установив базовый запрос, вы можете запустить объединение по всему дереву или указать другие соответствующие условия.


Однако не то, чтобы ref_id не должно было применяться ограничение FK. Корни и деревья управляются с помощью Tree и Node API, которые позаботятся обо всем этом для вас. SQL, который он выдаст для связанных столбцов NestedSet, выглядит примерно так:

CREATE TABLE category (id BIGINT AUTO_INCREMENT,  
ref_id INT, 
lft INT, 
rgt INT, 
level SMALLINT, 
PRIMARY KEY(id)) ENGINE = INNODB

Если вы хотите избавиться от головной боли, оставьте эти определения в столбцах (кроме имен, если это неприемлемо), вы избавите себя от головной боли. Если вам необходимо вернуться к новостям, используйте отдельный столбец / отношение, которое не связано с фактическим вложенным набором.

...