Nette database table více tabulek, join přes cizí klíč, nikoliv primární

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

Dobrý den,

už od včerejška se peru s Nette Database Table. V krátkosti popíšu strukturu tabulek a data které bych z nich chtěl dostat

Tabulka – orders:

id

Tabulka orders_products:

id product_id order_id

Tabulka products_images

product_id

Zde je můj kód pro získání dat v PHP

		$getOrders = $this->context->table("orders");



		foreach ($getOrders as $order)
		{
			echo $order->name;

			foreach($order->related("orders_products") as $op)
			{
				$image = $op->ref("products_images", "product_id");

			}
		}

z proměnné $image je patrné, že se chci dostat k tabulce products_images přes cizí klíč orders_products .product_id, ale mysql dotaz mi tam stále dává where id in.

Takto vypadá SQL dotaz se kterým nejsem spokojený:

SELECT *
FROM `products_images`
WHERE (`id` IN (58967, 58966))

Takto bych chtěl aby vypadal:

SELECT *
FROM `products_images`
WHERE (`product_id` IN (58967, 58966))

Funguje to ve chvíli kdy z tabulky products_images vyhodím primary key id a jako primary key dám product_id.

Jak to prosím mohu ovlivnit? Je můj přístup úplně mimo? Vím jak bych požadovaného výsledku dosáhl klasicky přes \Nette\Database\Connection.

Děkuji za Váš čas.

CZechBoY
Člen | 3608
+
0
-

Cizí klíče máš správně nastavené?

Rafan
Člen | 17
+
0
-

v tabulce orders_products mám cizí klíč order_id references orders(id) a product_id references products(id) v tabulce products_images mám cizí klíč product_id references products(id).

Je to tak správně?

CZechBoY
Člen | 3608
+
0
-

Tak ty chceš spíš všechny obrázky pro produkt, ne? Takže použij foreach+related namísto ref.

Rafan
Člen | 17
+
0
-

Upravil jsem kód a nyní mi vyhazuje Tracy:

No reference found for $orders_products->related(products_images).

Je teda zřejmé že mám něco špatně napříč těmi FK.

Přidám zde show create table tabulek orders_products a products_images (odstranil jsem přebytečné sloupce)

CREATE TABLE `orders_products` (
 PRIMARY KEY (`id`),
 KEY `order_id` (`order_id`),
 KEY `product_id` (`product_id`),
 CONSTRAINT `orders_products_ibfk_2` FOREIGN KEY (`order_id`) REFERENCES `orders` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
 CONSTRAINT `orders_products_ibfk_3` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=276 DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci
CREATE TABLE `products_images` (
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
KEY `product_id` (`product_id`),
CONSTRAINT `products_images_ibfk_1` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci

Pokud by jste měl chvilku čas se na to podívat, byl bych velmi vděčný.
Děkuji.

CZechBoY
Člen | 3608
+
0
-

Mně to jede jak jsem psal

/** @var ActiveRow $order */
foreach ($orders as $order) {
    echo $order->name;

    /** @var ActiveRow $op */
    foreach ($order->related('orders_products') as $op) {
        /** @var ActiveRow $pi */
        foreach ($op->related('products_images', 'product_id') as $pi) {
            var_dump($pi->toArray());
        }
    }
}
CREATE TABLE `orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) COLLATE utf8_czech_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;


CREATE TABLE `orders_products` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `order_id` int(11) NOT NULL,
  `product_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `order_id` (`order_id`),
  KEY `product_id` (`product_id`),
  CONSTRAINT `orders_products_ibfk_1` FOREIGN KEY (`order_id`) REFERENCES `orders` (`id`) ON DELETE CASCADE,
  CONSTRAINT `orders_products_ibfk_2` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;


CREATE TABLE `products` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) COLLATE utf8_czech_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;


CREATE TABLE `products_images` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `product_id` int(11) NOT NULL,
  `image` varchar(32) COLLATE utf8_czech_ci NOT NULL,
  PRIMARY KEY (`id`),
  KEY `product_id` (`product_id`),
  CONSTRAINT `products_images_ibfk_1` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;
Rafan
Člen | 17
+
0
-

Děkuji, chyběl mi tam parametr product_id v related. Vím, že toto řešení jsem už také zkoušel a problém je zde takový, že sice referenci najde ale v klauzuli IN jsou špatné hodnoty, protože tam vkládá hodnoty orders_products.id a ne orders_products.product_id.

hodnoty v tabulce orders_products:

|id|order_id|product_id|
|274|163|58967|
|275|163|58966|

PHP kód

foreach($orders_products->related("products_images", "product_id") as $products_images){}

Výsledek:

SELECT *
FROM `products_images`
WHERE (`products_images`.`product_id` IN (274, 275))

Dá se toto nějak ovlivnit?

Rafan
Člen | 17
+
0
-

Dobrý den, nikdo prosím nevíte? Stále se mi to nepodařilo vyřešit. Děkuji za případnou pomoc.

CZechBoY
Člen | 3608
+
0
-

Asi budeš muset jít ještě přes product tabulku.

Rafan
Člen | 17
+
0
-

Bohužel to už jsem také zkoušel:

		$getOrders = $this->context->table("orders");

		foreach ($getOrders as $order)
		{
			foreach($order->related("orders_products") as $orders_products)
			{
				echo $orders_products->name;

				foreach($orders_products->related("products", "id") as $p)
				{
					echo $p->price_vat; //nic nevypíše
				}

			}
		}

opět při dotazu na tabulku products dosazuje jako spojovací klíč orders_products.id nikoliv orders_products.product_id.

SELECT `id`
FROM `products`
WHERE (`products`.`id` IN (274, 275))

Zřejmě použití nette database není pro můj případ vhodné?

Děkuj za info.

CZechBoY
Člen | 3608
+
0
-

No já to takhle v šabloně nepoužívám… v modelu si vytvořim pole obecnýho typu (array nebo stdclass) a to potom v šabloně používám. Je to nezávislé na použité databázové vrstvě.

Rafan
Člen | 17
+
0
-

Také to mám v modelu (naplním si pole které metoda vrátí a pole pak používám v šabloně). Použití v šabloně se mi nelíbí, ale líbí se mi způsob výběru dat a spojení tabulek. Jinak to řeším tak, že si vyberu z tabulky orders na základě id vyberu produkty a k nim obrázky (klasicky přes left outer join), tím si naplním pole které metoda v modelu vrací. Mě se u tohoto způsobu líbilo že nemusím řešit joiny apod.

No ale budu se muset držet svého obvyklého postupu. I tak moc děkuji za pomoc.