Join a OrderBy pomocí Nette\Database

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
zacharo
Člen | 8
+
0
-

Zdravím,

už docela dlouho se snažím přijít na to jak se pomocí Nette/Database dá udělat jednoduchý sql příkaz typu

SELECT article.*, content.* FROM `article` INNER JOIN `content` ORDER BY date DESC

Prošel jsem dokumentaci i fórum, na jejichž základě jsem sestavil následující:

$this->connection->table('article')->select('article.*, content.*')->order('date ASC');

a s různými obměnami bez úspěchu zkoušel, nic nefungovalo. Všechny pokusy skončily s „Notice: Array to string conversion“ v laďence, v různých místech v závislosti na pokusu –normálně při výpisu v latte šabloně, při příkazu

$this->connection->table('article')->select('article.*, content.*')->order('date ASC')->getSql();

hned v daném místě.

Níže přidávám strukturu dotyčných tabulek.

CREATE  TABLE IF NOT EXISTS `crr`.`content` (
  `id` INT NOT NULL AUTO_INCREMENT ,
  `date` DATETIME NULL ,
  `user_id` INT NOT NULL ,
  PRIMARY KEY (`id`, `user_id`) ,
  UNIQUE INDEX `idcontent_UNIQUE` (`id` ASC) ,
  INDEX `fk_content_user_idx` (`user_id` ASC) ,
  CONSTRAINT `fk_content_user`
    FOREIGN KEY (`user_id` )
    REFERENCES `crr`.`user` (`id` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB

CREATE  TABLE IF NOT EXISTS `crr`.`article` (
  `id` INT NOT NULL AUTO_INCREMENT ,
  `title` VARCHAR(64) NULL ,
  `text` LONGTEXT NULL ,
  `subtext` VARCHAR(1024) NULL ,
  `articleCategory_id` INT UNSIGNED NOT NULL ,
  `content_id` INT NOT NULL ,
  PRIMARY KEY (`id`, `articleCategory_id`, `content_id`) ,
  UNIQUE INDEX `idarticle_UNIQUE` (`id` ASC) ,
  INDEX `fk_article_articleCategory1_idx` (`articleCategory_id` ASC) ,
  INDEX `fk_article_content1_idx` (`content_id` ASC) ,
  CONSTRAINT `fk_article_articleCategory1`
    FOREIGN KEY (`articleCategory_id` )
    REFERENCES `crr`.`articleCategory` (`id` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT `fk_article_content1`
    FOREIGN KEY (`content_id` )
    REFERENCES `crr`.`content` (`id` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;

Edit: Chyba nastane např. po volání metody count nad Selection:

$x = $this->connection->table('article')->select('article.*, content.*')->order('date ASC');
$pom = ($x->count());

Děkuji za pomoc

Editoval zacharo (26. 1. 2013 23:00)

Jakub Kontra
Člen | 30
+
0
-

->fetch(); :)

zacharo
Člen | 8
+
0
-
$this->connection->table('article')->select('article.*, content.*')->order('date ASC')->fetch();

Bohužel laděnka hlásí to samé: „Notice: Array to string conversion“

Chyba se vyskytuje v File: …/libs/Nette/Database/Drivers/MySqlDriver.php Line: 64

/**
* Delimites identifier for use in a SQL statement.
*/
public function delimite($name)
{
	// @see http://dev.mysql.com/doc/refman/5.0/en/identifiers.html
	return '`' . str_replace('`', '``', $name) . '`';
}
enumag
Člen | 2118
+
0
-

Verze Nette? Pokud stable, můžeš zkusit master?

zacharo
Člen | 8
+
0
-

Aplikaci jsem postavil na sandboxu ze stable verze 2.0.8 (staženo z webu cca týden zpět).

Problém přetrvává i po přechodu na vývojovou ‚master‘ větev.

enumag
Člen | 2118
+
0
-

Ok, tohle je bug. Jako nováček (dle počtu příspěvků) asi nebudeš schopen napsat test, že? Něco s tím provedu.

Btw. když u část ->select(...) prostě smažeš tak by to mělo fungovat.

Moment moment, jsem si nepřečetl pořádně ten kód… bug to sice je (nemělo by to házet takovou divnou notice) ale nevím co by to mělo udělat. V každém případě používáš to špatně. Smaž celou tu část ->select(...). Data z té tabulky content se pak tahají přes ref nebo related (podle toho co máš za relaci), případně místo ref lze použít reflexe (->content->...).

Editoval enumag (26. 1. 2013 23:43)

zacharo
Člen | 8
+
0
-

Jj, s Nette jsem začal minulý týden, zkouším se teď zorientovat.

Jinak ten dotaz bez toho selectu

$this->connection->table('article');

funguje, nicméně když chci řadit podle sloupce ‚date‘, který není v tabulce ‚article‘ ale je v té druhé ‚content‘, JOIN automaticky nenastane: příkaz

$this->connection->table('article')->order('date DESC');

vyhodí výjimku

PDOException #42S22
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'date' in 'order clause'

Je možné ty JOINy řešit nějakým alternativním způsobem v rámci \Nette\Database\Selection, nebo se musím uchýlit k psaní SQL dotazů ručně?

enumag
Člen | 2118
+
0
-

Základní nepochopení Nette\Database… S NDB se pracuje v podstatě bez joinů, respektive vytváří se automaticky když to potřebuješ ve where podmínkách. Pro účely získávání dat se ale s NDB pracuje tak, že se pouští nad každou tabulkou samostatný dotaz. Ne tak že bys je psal ručně přes $connection->table(…), ty dotazy se spustí automaticky při volání ref / related.

EDIT: Ne že by nešlo NDB donutit k joinům pro čtení, ale nedělej to. Raději zkus pochopit ten zamýšlený způsob, je mnohem lepší.

EDIT: Pro pochopení je podstatná tato část dokumentace, zejména ty dvě ukázky kódu. Efektivita už tě moc trápit nemusí a na API je lepší API dokumentace.

Editoval enumag (27. 1. 2013 0:01)

zacharo
Člen | 8
+
0
-

Ok, díky, podívám se na to.