Nette\Database, insert a PostgreSQL

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
PaBi3
Bronze Partner | 62
+
0
-

PostgreSQL databáza

create table a (
	id serial primary key,
	name varchar(40) not null
);

create table b (
	id serial primary key,
	name varchar(40) not null,
	a_id int not null references a(id) on update cascade on delete cascade
);

PHP kód

<?php
try {
	$db->exec('begin');
	$row = $db->table('a')->insert($data1);
	$row->related('b')->insert($data2);
	$db->exec('commit');

} catch (Exception $e) {
	$db->exec('rollback');
}
?>

Pri použití prvého insertu sa nezistí ID vkladaného záznamu do tabuľky a. Čiže druhý insert bude neúspešný. Je to spôsobené tým, že metóda lastInsertId() z PDO, ktorá je použitá tu vráti false, pretože potrebuje parameter, ktorý definuje názov sekvencie.

Navrhovaná oprava:

<?php
/**
 * Inserts row in a table.
 * @param  mixed array($column => $value)|Traversable for single row insert or TableSelection|string for INSERT ... SELECT
 * @return TableRow or FALSE in case of an error or number of affected rows for INSERT ... SELECT
 */
public function insert($data)
{
	if ($data instanceof TableSelection) {
		$data = $data->getSql();

	} elseif ($data instanceof \Traversable) {
		$data = iterator_to_array($data);
	}

	$return = $this->connection->query("INSERT INTO $this->delimitedName", $data);

	$this->rows = NULL;
	if (!is_array($data)) {
		return $return->rowCount();
	}

	$driver = $this->connection->getAttribute(\PDO::ATTR_DRIVER_NAME);
	if ($driver == 'pgsql') {
		$seq = $this->name . '_' . $this->primary . '_seq';
		/* alebo cez SELECT pg_get_serial_sequence($this->delimitedName, $this->delimitedPrimary */
	} else {
		$seq = NULL;
	}

	if (!isset($data[$this->primary]) && ($id = $this->connection->lastInsertId($seq))) {
		$data[$this->primary] = $id;
	}
	return new TableRow($data, $this);
}
?>

Nezisťoval som, či je možné nejakým spôsobom získať názov sekvencie, tak som sa držal konvencie, ktorú používa serial v PostgreSQL, t.j.: [tabulka]_[kluc]_seq.

EDIT: Zistil som, že je ešte nutné vyriešiť neexistujúce sekvencie. Inak PDO vyhodí výnimku v prípade, ak sa ukladá záznam do tabuľky, ktorá nemá sekvenciu. Možno by bolo najlepšie názov sekvencie udávať ako druhý parameter metódy insert().

Editoval PaBi3 (21. 1. 2011 15:55)

vrana
Člen | 131
+
0
-

V NotORM to řešit nebudu už jen proto, že insert má zabrané všechny parametry (to se používá pro vícehodnotový INSERT) a další konvenci se mi zavádět nechce. Záznamy lze vložit bez related po ručním získání lastInsertId:

<?php
$db->table('a')->insert($data1);
$data2["a_id"] = $db->lastInsertId("a_id_seq");
$db->table('b')->insert($data2);
?>
vrana
Člen | 131
+
0
-

Do NotORM jsem zavedl metodu NotORM_Structure::getSequence, pomocí které se to dá nastavit.

PaBi3
Bronze Partner | 62
+
0
-

Vďaka. Hneď sa s tým bude lepšie pracovať :-)