Yii Framework Forum: MANY - MANY - MANY Beziehung (II) - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

MANY - MANY - MANY Beziehung (II) Rate Topic: -----

#1 User is offline   yii 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 440
  • Joined: 25-July 09

Posted 06 October 2009 - 10:03 AM

bei diesem Code handelt es sich lediglich um ein Beispiel. Es geht darum eine Funktion zu schreiben die einen zweifachen JOIN ausführt.

Attached File  yii_many_many_many2.png (8.76K)
Number of downloads: 28

Artikel
id
baseform

Artikel_Warengruppe
artikelId
warengruppeId

Warengruppe
id
baseform

Warengruppe_Buyer
warengruppeId
buyerId

Buyer
id
name


Beispiel - Datensätze:
Artikel
  • Apfel
  • Birne
  • Gurken
  • Blumenkohl


Warengruppe
  • Obst
  • Gemüse


Buyer
  • Dieter
  • Helmut



SQL-CODE
CREATE TABLE Artikel
(
	id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
	baseform VARCHAR(128) NOT NULL
);

CREATE TABLE Warengruppe
(
	id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
	baseform VARCHAR(128) NOT NULL
);

CREATE TABLE Artikel_Warengruppe
(
	artikelId INTEGER NOT NULL,
	warengruppeId INTEGER NOT NULL,
	PRIMARY KEY (artikelId, warengruppeId),
	CONSTRAINT FK_artikel FOREIGN KEY (artikelId)
		REFERENCES Artikel (id),
	CONSTRAINT FK_warengruppe FOREIGN KEY (warengruppeId)
		REFERENCES Warengruppe (id)
);


CREATE TABLE Warengruppe_Buyer
(
	warengruppeId INTEGER NOT NULL,
	buyerId INTEGER NOT NULL,
	PRIMARY KEY (warengruppeId, buyerId),
	CONSTRAINT FK_warengrupep FOREIGN KEY (warengruppeId)
		REFERENCES Warengruppe (id),
	CONSTRAINT FK_buyer FOREIGN KEY (buyerId)
		REFERENCES Buyer (id)
);

CREATE TABLE buyer
(
	id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
	`name` VARCHAR(128) NOT NULL
);




SQL-Beispieldatensätze

INSERT INTO artikel(baseform) VALUES ( 'Apfel' );
INSERT INTO artikel(baseform) VALUES ( 'Birne' );
INSERT INTO artikel(baseform) VALUES ( 'Gurken' );
INSERT INTO artikel(baseform) VALUES ( 'Blumenkohl' );

INSERT INTO warengruppe(baseform) VALUES ( 'Obst' );
INSERT INTO warengruppe(baseform) VALUES ( 'Gemüse' );

INSERT INTO artikel_warengruppe(artikelId,warengruppeId) VALUES ( '1','1');
INSERT INTO artikel_warengruppe(artikelId,warengruppeId) VALUES ( '2','1');
INSERT INTO artikel_warengruppe(artikelId,warengruppeId) VALUES ( '4','2');

INSERT INTO buyer(`name`) VALUES ( 'Dieter' );
INSERT INTO buyer(`name`) VALUES ( 'Helmut' );

INSERT INTO warengruppe_buyer(warengruppeId,buyerId) VALUES ( '1','1');
INSERT INTO warengruppe_buyer(warengruppeId,buyerId) VALUES ( '1','2');
INSERT INTO warengruppe_buyer(warengruppeId,buyerId) VALUES ( '2','1');



So einen JOIN versuche ich zu realisieren:
SELECT artikel.baseform, warengruppe.baseform, buyer.name
	FROM artikel
	INNER JOIN artikel_warengruppe ON artikel.id = artikel_warengruppe.artikelId
	INNER JOIN warengruppe ON artikel_warengruppe.warengruppeId = warengruppe.id
	INNER JOIN warengruppe_buyer ON warengruppe.id = warengruppe_buyer.buyerId
	INNER JOIN buyer ON warengruppe_buyer.buyerId = buyer.id
	WHERE artikel.baseform LIKE 'Blumenkohl'


Model-Controller-View kommen noch
Meine Fragen stelle ich öffentlich und baue somit eine Wissensdatenbank für andere auf!
0

#2 User is offline   yii 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 440
  • Joined: 25-July 09

Posted 06 October 2009 - 10:32 AM

Artikel - Model
<?php

class artikel extends CActiveRecord
{
	/**
	 * The followings are the available columns in table 'artikel':
	 * @var integer $id
	 * @var string $baseform
	 */

	/**
	 * Returns the static model of the specified AR class.
	 * @return CActiveRecord the static model class
	 */
	public static function model($className=__CLASS__)
	{
		return parent::model($className);
	}

	/**
	 * @return string the associated database table name
	 */
	public function tableName()
	{
		return 'artikel';
	}

	/**
	 * @return array validation rules for model attributes.
	 */
	public function rules()
	{
		return array(
			array('baseform','length','max'=>128),
			array('baseform', 'required'),
		);
	}

	/**
	 * @return array relational rules.
	 */
	public function relations()
	{
		// NOTE: you may need to adjust the relation name and the related
		// class name for the relations automatically generated below.
		return array(
			'warengruppe'	=> array(self::MANY_MANY, 'warengruppe', 'artikel_warengruppe(artikelId, warengruppeId)',
				'together'	=> true,
				'joinType'	=> 'INNER JOIN',
			),
		);
	}

	/**
	 * @return array customized attribute labels (name=>label)
	 */
	public function attributeLabels()
	{
		return array(
			'id' => 'Id',
			'baseform' => 'Baseform',
		);
	}

public function artikelWarengruppeBuyer( $baseform )
{       
        return Artikel::model()->with(array('warengruppe', 'buyer'))->find('artikel.baseform=?', array( $baseform ) );
}
}

Meine Fragen stelle ich öffentlich und baue somit eine Wissensdatenbank für andere auf!
0

#3 User is offline   yii 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 440
  • Joined: 25-July 09

Posted 06 October 2009 - 10:32 AM

Buyer-Model
<?php

class buyer extends CActiveRecord
{
	/**
	 * The followings are the available columns in table 'buyer':
	 * @var integer $id
	 * @var string $name
	 */

	/**
	 * Returns the static model of the specified AR class.
	 * @return CActiveRecord the static model class
	 */
	public static function model($className=__CLASS__)
	{
		return parent::model($className);
	}

	/**
	 * @return string the associated database table name
	 */
	public function tableName()
	{
		return 'buyer';
	}

	/**
	 * @return array validation rules for model attributes.
	 */
	public function rules()
	{
		return array(
			array('name','length','max'=>128),
			array('name', 'required'),
		);
	}

	/**
	 * @return array relational rules.
	 */
	public function relations()
	{
		// NOTE: you may need to adjust the relation name and the related
		// class name for the relations automatically generated below.
		return array(
			'warengruppe'   => array(self::MANY_MANY, 'warengruppe', 'artikel_warengruppe(artikelId, warengruppeId)',
				'together'      => true,
				'joinType'      => 'INNER JOIN',
				),

		);
	}

	/**
	 * @return array customized attribute labels (name=>label)
	 */
	public function attributeLabels()
	{
		return array(
			'id' => 'Id',
			'name' => 'Name',
		);
	}
}

Meine Fragen stelle ich öffentlich und baue somit eine Wissensdatenbank für andere auf!
0

#4 User is offline   yii 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 440
  • Joined: 25-July 09

Posted 06 October 2009 - 10:33 AM

Warengruppe - Model
<?php

class warengruppe extends CActiveRecord
{
	/**
	 * The followings are the available columns in table 'warengruppe':
	 * @var integer $id
	 * @var string $baseform
	 */

	/**
	 * Returns the static model of the specified AR class.
	 * @return CActiveRecord the static model class
	 */
	public static function model($className=__CLASS__)
	{
		return parent::model($className);
	}

	/**
	 * @return string the associated database table name
	 */
	public function tableName()
	{
		return 'warengruppe';
	}

	/**
	 * @return array validation rules for model attributes.
	 */
	public function rules()
	{
		return array(
			array('baseform','length','max'=>128),
			array('baseform', 'required'),
		);
	}

	/**
	 * @return array relational rules.
	 */
	public function relations()
	{
		// NOTE: you may need to adjust the relation name and the related
		// class name for the relations automatically generated below.
		return array(
			'artikel'	=> array(self::MANY_MANY, 'artikel', 'artikel_warengruppe( artikelId, warengruppeId)',
				'together'	=> true,
				'joinType'	=> 'INNER JOIN',
			),
			'buyer'	=> array(self::MANY_MANY, 'buyer', 'warengruppe_buyer( warengruppeId, buyerId)',
				'together'	=> true,
				'joinType'	=> 'INNER JOIN',
			),
		);
	}

	/**
	 * @return array customized attribute labels (name=>label)
	 */
	public function attributeLabels()
	{
		return array(
			'id' => 'Id',
			'baseform' => 'Baseform',
		);
	}
}

Meine Fragen stelle ich öffentlich und baue somit eine Wissensdatenbank für andere auf!
0

#5 User is offline   yii 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 440
  • Joined: 25-July 09

Posted 06 October 2009 - 10:36 AM

Die relations() - Methode werde ich später vollständig ausfüllen

Folgende Befehle müssen noch ausgeführt werden

yiic shell index.php
crud artikel
crud warengruppe
crud buyer

Meine Fragen stelle ich öffentlich und baue somit eine Wissensdatenbank für andere auf!
0

#6 User is offline   yii 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 440
  • Joined: 25-July 09

Posted 06 October 2009 - 04:18 PM

Diesen Join muss ich irgendwie umsetzen.
SELECT artikel.baseform, warengruppe.baseform, buyer.name
        FROM artikel
        INNER JOIN artikel_warengruppe ON artikel.id = artikel_warengruppe.artikelId
        INNER JOIN warengruppe ON artikel_warengruppe.warengruppeId = warengruppe.id
        INNER JOIN warengruppe_buyer ON warengruppe.id = warengruppe_buyer.buyerId
        INNER JOIN buyer ON warengruppe_buyer.buyerId = buyer.id
        WHERE artikel.baseform LIKE 'Blumenkohl'



So ist es zwar falsch, aber ich weiß nicht wie ich das sonst machen soll!
	
public function artikelWarengruppeBuyer( $baseform )
{	
	return Artikel::model()->with(array('warengruppe', 'buyer'))->find('artikel.baseform=?', array( $baseform ) );
}

Meine Fragen stelle ich öffentlich und baue somit eine Wissensdatenbank für andere auf!
0

#7 User is offline   Dave 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 187
  • Joined: 09-October 08

Posted 07 October 2009 - 07:17 AM

Dann macht doch einfach findBySql()

AR dient doch nur dazu, das ganze einfach und übersichtlich zu halten.
0

#8 User is offline   yii 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 440
  • Joined: 25-July 09

Posted 07 October 2009 - 09:16 AM

View PostDave, on 07 October 2009 - 07:17 AM, said:

Dann macht doch einfach findBySql()

AR dient doch nur dazu, das ganze einfach und übersichtlich zu halten.


Wenn ich findBySql() benutze, dann benutze ich SQL-Code exakt für eine MySQL-Datenbank, somit wird mein Code nicht mehr benutzbar für andere Datenbanken (für den Fall, dass ich sie in ferne Zukunft ändern wollte).

Daher suche ich eine Lösung mit AR.
Meine Fragen stelle ich öffentlich und baue somit eine Wissensdatenbank für andere auf!
0

#9 User is offline   yoshi 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 170
  • Joined: 28-February 09
  • Location:Germany

Posted 16 October 2009 - 02:42 PM

Hallo yii,

entschuldige, dass ich mich erst jetzt damit befasse, ich hatte einiges um die Ohren.

Ich hab mir eine kleine Beispielanwendung und die Tabellen mit deinen Vorlagen angelegt.

Zunächst mal zu den groben Schnitzern in den Vorlagen:

1.

View Postyii, on 06 October 2009 - 04:18 PM, said:

Diesen Join muss ich irgendwie umsetzen.
SELECT artikel.baseform, warengruppe.baseform, buyer.name
        FROM artikel
        INNER JOIN artikel_warengruppe ON artikel.id = artikel_warengruppe.artikelId
        INNER JOIN warengruppe ON artikel_warengruppe.warengruppeId = warengruppe.id
        INNER JOIN warengruppe_buyer ON warengruppe.id = warengruppe_buyer.buyerId
        INNER JOIN buyer ON warengruppe_buyer.buyerId = buyer.id
        WHERE artikel.baseform LIKE 'Blumenkohl'


Diese Query funktioniert zwar, aber ich glaube nicht, dass es das ist, was du eigentlich haben möchtest.
Führst du diese Query mit den Tabellen/Daten von dir aus, erhälst du: Blumenkohl | Gemüse | Helmut
Ein Blick in die Tabellen verrät allerdings, das Helmut bisher nur Obst gekauft hat.
Folgender Fehler:
INNER JOIN warengruppe_buyer ON warengruppe.id = warengruppe_buyer.buyerId
->
INNER JOIN warengruppe_buyer ON warengruppe.id = warengruppe_buyer.warengruppeId

2.

View Postyii, on 06 October 2009 - 10:33 AM, said:

Warengruppe - Model
class warengruppe extends CActiveRecord
{
...
public function relations()
{
return array(
'artikel' => array(self::MANY_MANY, 'artikel', 'artikel_warengruppe( artikelId, warengruppeId)',
'together' => true,
'joinType' => 'INNER JOIN',
),
'buyer' => array(self::MANY_MANY, 'buyer', 'warengruppe_buyer( warengruppeId, buyerId)',
'together' => true,
'joinType' => 'INNER JOIN',
),
);
}
...
}


Immer den "eigenen" Fremdschlüssel zuerst angeben. Sprich:
'artikel' => array(self::MANY_MANY, 'artikel', 'artikel_warengruppe( warengruppeId, artikelId )',

Ansonsten würde der JOIN unter Verwendung von 'warengruppe.id = artikel_warengruppe.artikelId' durchgeführt, was natürlich Quatsch ergibt.

3. Bei der Relation in deinem Buyer-Model gehe ich mal von einem Copy'n'Paste-Fehler aus, richtig?! Schließlich hat der Buyer mit der Tabelle 'artikel_warengruppe' mal so garnichts am Hut.

So, nun zum eigentlichen Teil ;)

Du möchtest also bei Artikel anfangen und dich quasi an den Relationen "entlanghangeln" bis zum Käufer, ja?! Kein Problem! :)

Ich habe deine Funktion artikelWarengruppeBuyer() wie folgt verändert:
public function artikelWarengruppeBuyer( $baseform )
{       
    return Artikel::model()->with(array('warengruppe','warengruppe.buyer'))->findByAttributes(array('baseform'=>$baseform));
}

Sieht eigentlich genauso aus wie deine ;) Ob find() oder findByAttributes() bzw. je nach Anwendungsfall findAll() oder findAllByAttributes() ist dabei egal, der wesentlich Punkt ist 'warengruppe.buyer'.
Du hast versucht direkt die Relation 'buyer' anzugeben, aber zwischen dem Artikel und dem Käufer gibt es nunmal keine direkte Relation.
Aber es gibt eine zu 'warengruppe' und die wiederrum hat eine zu 'buyer', also gehen wir einfach über diese beiden Relationen hintereinander.

Zum Aufruf der dieser Funktion und um es etwas zu verdeutlichen habe ich mal folgenden Code zusammen geschustert:
$result = Artikel::model()->artikelWarengruppeBuyer('Apfel');
if(!empty($result))
{
    echo $result->baseform.' => ('; // baseform von Artikel ausgeben
    // MANY:MANY daher ist Warengruppe ein Array
    // Z.B. kann ein 'Apfel' in der Warengruppe 'Obst' UND in 'Genfood' sein.
    foreach($result->warengruppe as $a => $warengruppe1)
    {
        echo '( '.$warengruppe1->baseform.' ) => ( ';
        
        // MANY:MANY zwischen Warengruppe und Buyer
        // Z.B. kann 'Obst' von Meier,Schmitz und Müller gekauft worden sein,
        // während 'Genfood' von Meier und Schulze gekauft wurde.
        foreach($warengruppe1->buyer as $b => $buyer1)
            echo $buyer1->name.', ';
        echo ')';
    }
    echo ')';
}
else
    echo 'Keine Treffer';


Die Ausgabe für 'Apfel' (mit deinen Daten) sähe so aus:
Apfel => (( Obst ) => ( Dieter, Helmut, ))


Ich hoffe ich konnte dir damit ein bisschen weiterhelfen.
Weiterhin viel Erfolg und Spaß!

Gruß,
yoshi
2

#10 User is offline   yii 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 440
  • Joined: 25-July 09

Posted 18 October 2009 - 02:18 PM

Hi,
ja genau so habe ich es mir vorgestellt. Auf den Punkt wäre ich nie gekommen, dieser war zugleich mein Flaschenhals in der Anwendung.

public function artikelWarengruppeBuyer( $baseform )
{       
    return Artikel::model()->with(array('warengruppe','warengruppe.buyer'))->findByAttributes(array('baseform'=>$baseform));
}



Spaßig wird es nun sein, die Admin-Oberfläche dafür zuschreiben, sprich DELETE und EDIT.


thx!!!
Meine Fragen stelle ich öffentlich und baue somit eine Wissensdatenbank für andere auf!
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users