Hierarchie in Array packen

Da wird im Grunde dasselbe gemacht, nur dass die Berechnungen vorrausgesetzt werden bzw. erwartet wird, dass diese korrekt in PHP durchgeführt werden. Aber darauf basiert meine Einfüge-Funktion auch. Ich hatte das ja schon mal angedeutet.
In Ergänzung dazu:
Ist parent == previous, dann nehme lft des parent + 1 als lft des neuen Elements,
sonst nehme rgt des previous + 1 als lft des neuen Elements.

rgt des neuen Elements ist dann lft des neuen Elements + 1.

Damit kannst Du dann die beiden updates und das insert ausführen.

Gruß hpvw
 
Ok.. danke vielmals.. Die INSERT Funktion habe ich schon mal fertig :)
Nachem ich nun schon INNODB verwende, möchte ich die 3 SQL Queries die für den Insert nötig sind in eine atomare Funktion bündeln (mittels Transaktionssteuerung).

Transaction-Lock
Habe mir das auf mysql.com angesehen, werde aber nicht schlau daraus...
Kannst Du mir einen Tipp geben, wo Du welchen Befehl (BEGIN, COMMIT, ROLLBACK) und die Fehlerabfragen setzen würdest? Wenn ich das mal haben, durchschau ich wenigstens das ganze Prinzip ;)

Hier die SQL Queries (ohne Fehlerabfrage und ohne Transaction-Lock):
PHP:
// 1. Platz für den neuen Knoten erzeugen
		//-------------------------------------------------------------------
		$sql = ' UPDATE '
			. ' `tbl_product_category` '
			. ' SET '
			. ' `product_category_rgt_order`=(`product_category_rgt_order`+2) '
			. ' WHERE `product_category_rgt_order`>=\''.$startParentNodeRgt.'\' ';
		$this->_db->query($sql);
		
		$sql = ' UPDATE '
			. ' `tbl_product_category` '
			. ' SET '
			. ' `product_category_lft_order`=(`product_category_lft_order`+2) '
			. ' WHERE `product_category_lft_order`>=\''.$startParentNodeRgt.'\' ';
		$this->_db->query($sql);
		
		// 2. Neuen Knoten in die Datenbank einfügen
		//-------------------------------------------------------------------
		$sql = ' INSERT INTO '
			. ' `tbl_product_category` '
			. ' (`product_category_lft_order`, `product_category_rgt_order`, `testtext`) '
			. ' VALUES '
			. ' (\''.$startParentNodeRgt.'\', \''.($startParentNodeRgt+1).'\', \''.$nodeName.'\') ';
		echo $sql;
		$this->_db->query($sql);

Wie Du siehst wird jeder Query einzeln ausgeführt.

Mein Ziel wäre in etwa (sofern mein Gedankengang dahinter richtig ist):
1. Tabellen sperren
2. Begin Transaction
3. Update Query 1
4. Update Query 2
5. Insert Query
6. On Error: Rollback
7. Else: Commit
8 Tabellen freigeben

Nur hab ich keinen Plan ob das semantisch stimmt und ob wie ich es syntaktisch angehen kann!?

Ciao,
Mike
 
Ich habe es so gemacht:
Am Anfang 3 Queries ausführen:
LOCK TABLE
SET AUTOCOMMIT=0
BEGIN

Dann habe ich bei jedem weiteren Query geprüft, ob es false zurückliefert.
In dem Fall:
ROLLBACK
SET AUTOCOMMIT=1
UNLOCK TABLE
Ausstieg aus der Funktion (return false)

Am Ende der Funktion:
COMMIT
SET AUTOCOMMIT=1
UNLOCK TABLE
return: die neue id

Du kannst natürlich auch mitprotokollieren, ob irgendwo ein Fehler aufgetreten ist und dann am Ende wahlweise einen ROLLBACK oder ein COMMIT machen.

Gruß hpvw
 
Hi,

Danke, so weit habe ich das verstanden..
Mich wundert nur eines: Warum machst Du einen TABLE LOCK und keinen ROW LEVEL LOCK?

Hat das irgendeinen speziellen Sinn (Außer das man möglichen Deadlocks vorbeugt)?
Weil eigentlich bremsen Table Locks ein System ja unnötig aus (da ja alle Datensätze somit für andere Transaktionen gesperrt sind).
Wenn Du z.B. eine Tabelle mit 10.000 Datensätzen hast, mit deiner Transaktion aber nur 3 änderst, blockst Du trotzdem die restlichen 99.997 Datensätze für andere Requests!?

LG
Mike
 
Gründe:
  • Mit dem TABLE LOCK bin ich auf der sicheren Seite.
  • In den Anwendungen, die ich bisher mit dem MPTT gemacht habe und die ich noch so im Kopf habe, gibt es sehr wenig Updates, so dass man die kurzfristige totale Blockade verschmerzen kann.
  • Bei den Updates sind im Mittel mehr als die Hälfte der Datensätze des Baumes betroffen, so dass ich mir weitere Gedanken spare und nicht viel verliere, wenn ich einfach die ganze Tabelle sperre.
Gruß hpvw
 
Es ist wirklich so traurig...
Bin gespannt ob ich das zum Laufen bekomm.. Aber das Teil stellt echt kongeniale Methoden zur verfügung.. Hier ein kleiner Auszug:

DB_NestedSet::createLeftNode()
Creates a node before a given node

DB_NestedSet::createRightNode()
Creates a node after a given node

DB_NestedSet::deleteNode()
Deletes a node

DB_NestedSet::createSubNode()
Creates a subnode

DB_NestedSet::moveTree()
Wrapper for node moving and copying

etc. etc....
 
Mik3e hat gesagt.:
Was hältst Du davon?
Das kann ich nicht beurteilen. Ich bin immer ganz schlecht darin, mich mit fremdem Code zu beschäftigen bzw. solch umfangreiche Pakete in meine Anwendungen zu integrieren. Daher und wegen des Lerneffekts baue ich mir die Dinge, die ich brauche, lieber selbst. Ich will das Modell auch richtig verstehen, wenn ich damit umgehe.

Gruß hpvw
 
Hi HP..

Noch ne Möglichkeit um festzustellen, ob ein Knoten Kiner hat:
rgt-lft > 1 ............ Hat Kinder (true)

Anbei noch ein Screenshot vom Nested Set Output.. Ist schon ganz nett und vor allem verdammt schnell (da es nur ein einziges SQL Statement ohne jegliche Rekursion ist ;)

Ciao,
Mike
 

Anhänge

  • nestedSetResult.jpg
    nestedSetResult.jpg
    112 KB · Aufrufe: 67
Hi,

Hier ist das ganze besser untergebracht :)
Ich bin mir noch nicht ganz im Klaren, wie ich die Oberfläche für den Benutzer gestalten soll...

Bisher bin ich von drei verschiedenen Möglickeiten der Verschiebung ausgegangen:
1. Teilbaum als NEUES KIND VON Knoten XY anlegen
2. Teilbaum EINE POSITION VOR Knoten XY verschieben
3. Teilbaum EINE POSITION NACH Knoten XY verschieben

Der User muss ja die Möglichkeit haben, Knoten vertikal und horizontal zu verschieben.

Anbei eine kleine Grafik zum Verschieben eines Knotens ALS NEUES KIND VON xy..
Damit meine ich eine vertikale Verschiebung.
Horizontal wäre z.B. die beiden Bäume "Auto" und "Motorrad" zu drehen... (d.h. zuerst kommt "Motorrad" und dann "Auto".

Ciao,
Mike
 

Anhänge

  • MPTTMoveExample.jpg
    MPTTMoveExample.jpg
    88,2 KB · Aufrufe: 39
Zurück