Отношения Zend Framework - определение имен столбцов в findManyToManyRowset ()?

Я работаю над приложением, разработанным с использованием Zend Framework. Я определил отношения в моделях и могу с удовольствием их использовать, например:

$rowset = $row->findManyToManyRowset('People', 'Jobs');

Однако я столкнулся с проблемой, когда возвращаемый набор строк имеет имена столбцов, которые совпадают в «Люди» и «Работа», и, следовательно, объединяет ключи массива, теряя некоторые данные из окончательного набора строк.

Я понимаю, что могу передать объект Zend_Db_Select в findManyToManyRowset() в качестве одного из параметров, но не могу найти никакой документации, объясняющей, как его использовать в этом случае, например:

$select = $this->select()->from(array(
                                     'p' => 'people', 
                                     'j' => 'jobs'
                                     ),
                                array( 
                                     'person_id' => 'p.id',
                                     'job_id' => 'j.id',
                                     'person_code' => 'p.code',
                                     'job_code' => 'j.code'
                                     )
                                );  

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

Error: No reference rule "" from table People to table Jobs

Может ли кто-нибудь просветить меня о том, как это должно быть сделано? Я знаю, что могу изменить имена столбцов в базе данных, но я бы предпочел изменить код, а не перепроектировать структуру моей БД и обновить весь связанный код.

Примечание. Без какой-либо формы псевдонима столбца, как указано выше, возвращаемый набор строк выглядит следующим образом (т. е. он объединяет столбцы с одинаковыми именами):

[_data:protected] => Array
    (
        [id] => 1
        [code] => SX342
    )

С уважением,
Мэтт


person fistameeny    schedule 17.09.2009    source источник


Ответы (2)


Моя первая рекомендация заключается в том, что вы не должны называть столбцы такими общими именами, как id и code. Эти имена бессмысленны, и, как вы уже поняли, они также приводят к коллизиям при выборке результатов в ассоциативном массиве.

Вы также неправильно используете интерфейс Select. Вы должны указать только одну таблицу на вызов from() или вызов join().

Наконец, я никогда не пытаюсь выполнять сложные запросы через интерфейс отношений Zend_Db_Table. Он предназначен только для простых случаев. Если у вас есть более сложный запрос, просто напишите SQL-запрос явно.

См. также Как сделать объединенный запрос в интерфейсе таблиц ZF?

person Bill Karwin    schedule 10.10.2009
comment
Спасибо за ответ Билл. Есть ли у вас какие-либо рекомендации о том, как следует называть столбцы, или, в более широком смысле, рекомендации по хорошим руководствам по передовым методам проектирования баз данных? - person fistameeny; 11.10.2009
comment
Например, вы можете использовать person_id в обеих таблицах вместо person_id в одной таблице и id в другой таблице. Там, где это возможно, столбцы с одинаковым содержимым должны иметь одинаковые имена во всех таблицах. Точно так же и person_code вместо простого кода. По сути делайте имена столбцов разными для разных таблиц, по крайней мере, если это таблицы, которые могут быть объединены вместе в запросе. - person Bill Karwin; 11.10.2009
comment
Прочтите первую главу «Стили программирования SQL для Smarties» Джо Селко. Google Книги включают первую главу в предварительную онлайн-версию: books.google.com/books?id=a9jtyioHfp8C< /а> - person Bill Karwin; 11.10.2009
comment
person.id не лишен смысла, имхо - person Josh; 16.06.2014

Я знаю, что этот ответ приходит немного поздно, но вот некоторые вещи, на которые следует обратить внимание.

1) findManyToManyRowset($matchTable, $intersectionTable, $callerRefRule, $matchRefRule, $select); -- если вы проходите Zend_Db_Table_Select, вы захотите пройти null по правилам.

2) Zend_Db_Table_Select, переданное в findManyToManyRowset(), должно быть создано из $matchTable, и можно с уверенностью предположить, что в предложениях where i является псевдонимом для таблицы пересечений, а m является псевдонимом для таблицы соответствий.

3) В случае коллизий m выиграет имя ключа в ассоциативном массиве, возвращаемом в php. Выполненный запрос выглядит так:

  SELECT 
    `i`.*, `m`.* 
  FROM 
    `interscetTable` AS `i` 
  INNER JOIN 
    `matchTable` AS `m` 
  ON
    `i`.`fk_m` = `m`.`pk` WHERE (`i`.`fk_o` = ?)  

4) Несмотря ни на что, возвращаемое значение findManyToManyRowset() будет набором строк, созданным из $matchTable, поэтому, если вам нужно захватить какую-либо информацию из пересекающейся таблицы, а также захватить данные для таблицы соответствия, вам, вероятно, понадобится custom Zend_Db_Select и в любом случае избегайте использования материала Zend_Db_Table для сопоставления данных.

Итак, рабочий пример, использующий «Люди» в качестве таблицы соответствия, «Рабочие» в качестве таблицы пересечений и скажем «Клиенты» в качестве исходной таблицы. Предположим для этого примера, что таблицы связаны друг с другом примерно так: Люди.id:... -> рабочие.person_id:client_id:job_id -> клиенты:id:...

$client = $clientTable->fetchRow(); /// grab a random client

// fetch all people that have worked for the client ordered by their last name.
$client->findManyToManyRowset("People", "Workers", null, null, 
  $peopleTable->select()->order('m.lastname')); 

// fetch all people that have worked for the client ordered by their hire date:
// `workers`.`hiredate`
$client->findManyToManyRowset("People", "Workers", null, null, 
  $peopleTable->select()->order('i.hiredate')); 
person gnarf    schedule 25.02.2010