Рефлексивные отношения «многие ко многим» в CakePHP

Я искал подробный ответ на этот вопрос, но не смог его решить. Недавно я работал с (и учился) CakePHP и сталкивался с препятствиями. Чтобы упростить мою базу данных, допустим, у нас просто две таблицы:

relationships persons (или persons_persons )

У людей есть много-много отношений с самим собой – и действительно, у двух человек может быть более чем одна взаимосвязь между собой:

 persons ------- *person_id* name relationships ------------- *relationship_id* person_1_id person_2_id start_date end_date 

Теперь, если я хочу сказать, что Person1 (id = 1) женат на Person2, у меня будет одна запись в таблице relationships . person_1_id1 , а person_2_id – два.

Я могу создать эти отношения в CakePHP и показать списки отношений (и лиц) на запись Person. Однако это однонаправленное отношение: для Лица 1 запрос будет только тянуть объекты Relationship где соответствует person_1_id . Если я хочу запросить отношения для Person 2, мне придется иметь вторую идентичную строку с person_1_id и person_2_id .

Вот модели:

 class Member extends AppModel { public $hasMany = array( 'Relationships' => array( 'className' => 'Relationship', 'foreignKey' => 'person_1_id' ) ); } class Relationship extends AppModel { public $belongsTo = array( 'Person1' => array( 'className' => 'Person', 'foreignKey' => 'person_1_id' ), 'Person2' => array( 'className' => 'Person', 'foreignKey' => 'person_2_id' ) ); } 

Какие-либо предложения? Логически не логично дублировать объекты связи, когда person_1_id на самом деле не является отдельным, чем person_2_id.

Solutions Collecting From Web of "Рефлексивные отношения «многие ко многим» в CakePHP"

Я думаю, у вас есть два варианта:

1. Дублировать запись отношения

Посмотрите на это с другой точки зрения; Рассмотрим понятие направленного против неориентированного графа. Ваша текущая схема поддерживает направленный край, оставляя один объект (Person) и прибывая на другой. Согласившись с точки зрения вашего приложения, человек не может иметь отношения с другим, не зная его.

Объем пространства в базе данных был бы незначительным, если бы вы решили пойти по этому маршруту и ​​было бы менее сложно реализовать, чем вариант 2. Не стоит забывать, что вы должны принять меры для обеспечения того, чтобы отношения оставались симметричными в любое время.

2. Обращайтесь с асимметрией отношений в своем приложении

Создайте еще одно соотношение, чтобы ваша модель выглядела следующим образом:

 class Member extends AppModel { public $hasMany = array( 'RelationshipsA' => array( 'className' => 'Relationship', 'foreignKey' => 'person_1_id' ), 'RelationshipsB' => array( 'className' => 'Relationship', 'foreignKey' => 'person_2_id' ) ); } 

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

Мне жаль, что я не могу быть более полезным, но я не могу придумать голову, как реализовать неориентированный граф, не создавая его поверх направленного.

Обновление 05/05/13

Чтобы суммировать поток комментариев, установка finderQuery в ассоциации hasMany может замаскировать необходимость дублирования поиска для связи с person_2_id ( Documentation ):

 'Relationship' => array( 'finderQuery' => 'SELECT Relationship.* FROM relationships AS Relationship WHERE Relationship.person_2_id = {$__cakeID__$} OR Relationship.person_1_id = {$__cakeID__$};' ) 

Это скрывает сложный механизм поиска, но для хранения отношений может потребоваться дальнейшая мысль.