Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [ZendFramework]Mysql i relacje
Forum PHP.pl > Forum > PHP > Frameworki
ShadowD
Trochę ułatwię sprawę na potrzeby stwierdzenie "czego najlepiej użyć", mamy następujące tabele:

PAGE
- id
- idStatus
- name
- value

STATUS
- id
- statusName

Jak najlepiej pobrać całość w jednym zapytaniu?

1. Jojn w zapytaniu
2. Coś takiego - http://blog.wilgucki.pl/2010/11/zenddb-i-relacje.html tutaj wydaje mi się że jest to bardziej do relacji 1:n
3. Pod zapytanie

Mam takie trzy możliwości, w każdej jest to do wykonania, ale nie wiem która z nich będzie najbardziej poprawna przy relacji 1:n wybrał bym #1 lub #2 w zależności od skomplikowania (z przewagą dla #2) a tutaj za skarby nie mogę się zdecydować, problem może nawet nie zendowski więc jak ukochani moderatorzy postanowią przenieść nie pogniewam się. (I nie ma tutaj sarkazmu :])
mortus
Niestety pod względem wydajności najsłabiej wypadną relacje tworzone przez ZF, a to dlatego, że wydobycie statusów dla każdej strony to w tym przypadku wykonywanie odrębnych zapytań SELECT dla każdej ze strony. Potwierdzeniem niech będzie odpowiedni fragment kodu (linia 54):
  1. /**
  2.   * Query a dependent table to retrieve rows matching the current row.
  3.   *
  4.   * @param string|Zend_Db_Table_Abstract $dependentTable
  5.   * @param string OPTIONAL $ruleKey
  6.   * @param Zend_Db_Table_Select OPTIONAL $select
  7.   * @return Zend_Db_Table_Rowset_Abstract Query result from $dependentTable
  8.   * @throws Zend_Db_Table_Row_Exception If $dependentTable is not a table or is not loadable.
  9.   */
  10. public function findDependentRowset($dependentTable, $ruleKey = null, Zend_Db_Table_Select $select = null)
  11. {
  12. $db = $this->_getTable()->getAdapter();
  13.  
  14. if (is_string($dependentTable)) {
  15. $dependentTable = $this->_getTableFromString($dependentTable);
  16. }
  17.  
  18. if (!$dependentTable instanceof Zend_Db_Table_Abstract) {
  19. $type = gettype($dependentTable);
  20. if ($type == 'object') {
  21. $type = get_class($dependentTable);
  22. }
  23. require_once 'Zend/Db/Table/Row/Exception.php';
  24. throw new Zend_Db_Table_Row_Exception("Dependent table must be a Zend_Db_Table_Abstract, but it is $type");
  25. }
  26.  
  27. // even if we are interacting between a table defined in a class and a
  28. // table via extension, ensure to persist the definition
  29. if (($tableDefinition = $this->_table->getDefinition()) !== null
  30. && ($dependentTable->getDefinition() == null)) {
  31. $dependentTable->setOptions(array(Zend_Db_Table_Abstract::DEFINITION => $tableDefinition));
  32. }
  33.  
  34. if ($select === null) {
  35. $select = $dependentTable->select();
  36. } else {
  37. $select->setTable($dependentTable);
  38. }
  39.  
  40. $map = $this->_prepareReference($dependentTable, $this->_getTable(), $ruleKey);
  41.  
  42. for ($i = 0; $i < count($map[Zend_Db_Table_Abstract::COLUMNS]); ++$i) {
  43. $parentColumnName = $db->foldCase($map[Zend_Db_Table_Abstract::REF_COLUMNS][$i]);
  44. $value = $this->_data[$parentColumnName];
  45. // Use adapter from dependent table to ensure correct query construction
  46. $dependentDb = $dependentTable->getAdapter();
  47. $dependentColumnName = $dependentDb->foldCase($map[Zend_Db_Table_Abstract::COLUMNS][$i]);
  48. $dependentColumn = $dependentDb->quoteIdentifier($dependentColumnName, true);
  49. $dependentInfo = $dependentTable->info();
  50. $type = $dependentInfo[Zend_Db_Table_Abstract::METADATA][$dependentColumnName]['DATA_TYPE'];
  51. $select->where("$dependentColumn = ?", $value, $type);
  52. }
  53.  
  54. return $dependentTable->fetchAll($select);
  55. }

W osobnym temacie natomiast toczymy dyskusję na temat wyższości JOIN-ów nad PODZAPYTANIAMI, czy też odwrotnie i moje wstępne testy wykazały, że złączenia są szybsze/bardziej wydajne. Osobiście tego się właśnie spodziewałem i w związku z tym faktem polecam złączenia.
ShadowD
Ok, zdecydowałem się na połączenie jein'em, rozumiem że joinLeft() będzie najlepszym rozwiązaniem, mamy jeszcze join() i inne pochodne.

Mam tylko jeden problem, może ktoś zna obejście problemu.

Kod modelu
  1. protected $_name = 'page';
  2.  
  3. public function getPage($name)
  4. {
  5. $select = $this->select()
  6. ->from('page',array('name', 'template', 'time', 'title', 'value'))
  7. ->where('name="'.$name.'"')
  8. ->setIntegrityCheck(false)
  9. ->joinLeft(array('status'=>'pageStatus'), 'page.idStatus = status.id',array('statusName'=>'name', 'statusActive'=>'active'))
  10. ->joinLeft(array('seo'=>'pageSeo'), 'page.idSeo = seo.id',array('seoTitle'=>'title', 'seoDescription'=>'description', 'seoKeywords'=>'keywords', 'seoFallow'=>'follow', 'seoIndex'=>'index'));
  11.  
  12. return $this->fetchRow($select)->toArray();
  13. }
  14. }


W tabeli page i pageStatus mam pole o takiej samej nazwie "name" próbuję zmienić jego nazwę na "statusName" (w tabeli status) dostaję komunikat o błędzie:
Message: SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'name' in where clause is ambiguous

Po zmianie nazwy pola na "nazwa2" wszystko działa jak powinno, jest opcja by zachować takie same nazwy pól i jakoś przy pobieraniu je zmienić?
Psajkus
Masz w dwóch tabelach pole o takiej samej nazwie. W Twoim zapisie nie wiadomo więc do którego pola odnosi się warunek. Wystarczy, że podasz nazwę tabeli:

  1. ->where('page.name LIKE ?', $name)


lub też

  1. ->where('pageStatus.name LIKE ?', $name)
ShadowD
Próbowałem błąd identyczny był. :-<
mortus
Przed return-em wypisz zapytanie (w linii 11):
  1. echo $select;

I powinieneś zobaczyć, co jest nie tak.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.