Laravel speichere / aktualisiere viele zu viele Beziehungen

85

Kann mir jemand helfen, wie man viele zu viele Beziehungen rettet? Ich habe Aufgaben, Benutzer können viele Aufgaben haben und Aufgabe kann viele Benutzer haben (viele zu viele). Was ich erreichen möchte, ist, dass der Administrator in Aktualisierungsform mehrere Benutzer einer bestimmten Aufgabe zuweisen kann. Dies erfolgt über eine HTML-Mehrfachauswahl-Eingabe

name="taskParticipants[]"

Der Haken dabei ist, dass Sie über dasselbe Formular (Eingabe) Benutzer hinzufügen / entfernen können. Deshalb muss ich sync () verwenden. Vielleicht sollte ich von vorne anfangen, weiß aber nicht, wo ich anfangen soll ...

Dies ist mein Benutzermodell:

public function tasks()
{
    return $this->belongsToMany('Task','user_tasks');
}

Aufgabenmodell

public function taskParticipants()
{
    return $this->belongsToMany('User','user_tasks');
}

TaskController

public function update($task_id)
{
    if (Input::has('taskParticipants'))
    {
        foreach(Input::get('taskParticipants') as $worker)
        {
            $task2 = $task->taskParticipants->toArray();
            $task2 = array_add($task2,$task_id,$worker);
            $task->taskParticipants()->sync(array($task2));
        }
    }
}

Dies ist die Struktur der Tabellenaufgaben ID | Titel | Frist

user_tasks
id|task_id|user_id
SuperManSL
quelle
Ich habe meinen Code aktualisiert. Link
SuperManSL
4
$workers = Input::get('taskParticipants'); $task->taskParticipants()->sync($workers);und das ist alles, was Sie brauchen, solange Sie von diesem Formular alle Benutzer übergeben, die der Aufgabe zugewiesen sind.
Jarek Tkaczyk
@ JarekTkaczyk Danke, das war magisch.
Ryu_hayabusa

Antworten:

190

tldr; Verwendung syncmit 2. Parameterfalse


Viele-zu-viele-Beziehungen bestehen belongsToManybei beiden Modellen:

// Task model
public function users()
{
  return $this->belongsToMany('User', 'user_tasks'); // assuming user_id and task_id as fk
}

// User model
public function tasks()
{
  return $this->belongsToMany('Task', 'user_tasks');
}

Um eine neue Beziehung hinzuzufügen, verwenden Sie attachoder sync.

Der Unterschied zwischen den beiden ist:

1 attach fügt der Pivot-Tabelle eine neue Zeile hinzu, ohne zu überprüfen, ob sie bereits vorhanden ist. Es ist gut, wenn Sie zusätzliche Daten mit dieser Beziehung verknüpft haben, zum Beispiel:

Userund Exammit Pivot-Tabelle verbundenattempts: id, user_id, exam_id, score

Ich nehme an, das ist nicht das, was Sie in Ihrer Situation brauchen:

$user->tasks()->getRelatedIds(); // [1,2,3,4,5,6]

$user->tasks()->attach([5,6,7]);
// then
$user->tasks()->getRelatedIds(); // [1,2,3,4,5,6,5,6,7]

2 sync hingegen entfernt entweder alle Relationen und richtet sie neu ein:

$user->tasks()->getRelatedIds(); // [1,2,3,4,5,6]

$user->tasks()->sync([1,2,3]);
// then
$user->tasks()->getRelatedIds(); // [1,2,3]

oder es werden neue Beziehungen eingerichtet, ohne das vorherige UND zu trennen, ohne Duplikate hinzuzufügen:

$user->tasks()->sync([5,6,7,8], false); // 2nd param = detach
// then
$user->tasks()->getRelatedIds(); // [1,2,3,4,5,6,7,8]
Jarek Tkaczyk
quelle
8
Es wäre schön, wenn dies in den Hauptdokumenten und nicht in den API-Dokumenten dokumentiert wäre! Mach weiter. +1.
Ceejayoz
Ich mag die zweite Lösung mit Synchronisation und dem zweiten Parameter sehr. Wie ich im Kommentar unten sagte, kann ich es mir nicht leisten, nicht zu trennen. Die Geschichte ist, dass der Administrator den Benutzern Aufgaben zuweisen kann. Er wählt Benutzer aus der Dropdown-Liste (mehrere) aus, Feld ist Teilnehmer []. Also ...: Schritt 1: Der Administrator weist Aufgabe A drei Benutzern zu (Ihre Methode funktioniert, wir haben 3 Datensätze in der Datenbank). Schritt 2: Der Administrator aktualisiert Aufgabe A und fügt zwei Benutzer hinzu (Ihre Methode funktioniert, wir haben 5 Datensätze in der Datenbank). Schritt 3: Der Administrator aktualisiert Aufgabe A und entfernt 1 Benutzer (Ihre Methode schlägt fehl, wir haben immer noch 5 Benutzer anstelle von 4). Meine Aktualisierungsmethode Mein Code
SuperManSL
1
Sie können Ihre Beziehungsabfrage vereinfachen, $this->belongsToMany('User')task_useruser_tasks
indem
@Rok Wenn Sie immer ein Array aller verwandten Benutzer übergeben, dann verwenden Sie syncmit dem Trennen, keine Sorge. Ich schlage vor, den 2. Parametersatz auf false zu setzen, wenn Sie "neue Aufgabe für einen Benutzer hinzufügen" oder "Benutzer einer Aufgabe zuweisen" möchten, wenn Sie ideines der zugehörigen Modelle übergeben.
Jarek Tkaczyk
1
@FabioAntunes syncgibt einen Array mit detached, attachedund updatedListen. attachgibt nichts zurück, aber in beiden Fällen würden Sie eine Ausnahme erhalten, wenn in den Datenbankaufrufen etwas Unerwartetes passiert.
Jarek Tkaczyk
104

Hier sind meine Hinweise zum Speichern und Aktualisieren aller eloquenten Beziehungen.

in Eins zu Eins :

Sie müssen HasOne für das erste Modell und BelongsTo für das zweite Modell verwenden

Datensatz auf dem ersten Modell (hinzuzufügen hasOne ) verwenden die  Sparfunktion

Beispiel:    $post->comments()->save($comment);

Aufzeichnung auf dem zweiten Modell (hinzuzufügen Gehört ) verwenden , um die  assoziierten Funktion

Beispiel:    $user->account()->associate($account);    $user->save();


in Eins zu Viele :

Sie müssen HasMany für das erste Modell und BelongsTo für das zweite Modell verwenden

Verwenden Sie die Funktionen save  oder saveMany , um einen Datensatz in der ersten Tabelle ( HasMany ) hinzuzufügen

Beispiel:    $post->comments()->saveMany($comments);

Aufzeichnung auf dem zweiten Modell (hinzuzufügen Gehört ) verwenden , um die  assoziierten Funktion

Beispiel:    $user->account()->associate($account);    $user->save();


in Viele zu Viele :

Sie müssen  BelongsToMany für das erste Modell und BelongsToMany für das zweite Modell verwenden

Verwenden Sie zum Hinzufügen von Datensätzen zur Pivot-Tabelle die Funktionen zum Anhängen oder Synchronisieren

  • Beide Funktionen akzeptieren einzelne IDs oder Arrays von IDs 

  • Der Unterschied besteht darin, zu prüfen, ob der Datensatz bereits in der Pivot-Tabelle vorhanden ist, während die Synchronisierung dies nicht tut

Beispiel: $user->roles()->attach($roleId);


im polymorphen Eins zu Viele :

Sie müssen  MorphMany für das Hauptmodell und  MorphTo für alle (*** fähigen) Modelle verwenden

Verwenden Sie das Speichern , um Datensätze für alle anderen Modelle hinzuzufügen 

Beispiel:    $course->tags()->save($tag);

Die Pivot-Tabelle sollte die folgenden Spalten enthalten:

. Hauptmodell-ID

. (*** fähig) ID

. (*** fähig) Typ


in polymorphen vielen zu vielen :

Sie müssen  MorphByMany für das Hauptmodell und  MorphToMany für alle (*** fähigen) Modelle verwenden

Um Datensätze für alle anderen Modelle hinzuzufügen, verwenden Sie save oder saveMany

Beispiel:    $course->tags()->save($tag);

Beispiel:    $course->tags()->saveMany([$tag_1, $tag_2, $tag_3]);

Die Pivot-Tabelle sollte die folgenden Spalten enthalten:

. Hauptmodell-ID

. (*** fähig) ID

. (*** fähig) Typ


in Hat viele durch (Abkürzung):

Sie müssen HasManyThrough für die erste Tabelle verwenden und die normalen Beziehungen für die anderen beiden Tabellen haben

Dies funktioniert nicht für ManyToMany- Beziehungen (wo es eine Pivot-Tabelle gibt).

Dafür gibt es jedoch eine schöne und einfache Lösung.


Hier ist ein Artikel, den ich geschrieben habe, inspiriert von dieser Antwort. Es ist wichtig, dies zu überprüfen: https://hackernoon.com/eloquent-relationships-cheat-sheet-5155498c209

Mahmoud Zalt
quelle
Ich habe diese Antwort tatsächlich platziert, als sie bereits über 40 Likes auf die richtige Antwort hatten, aber ja, ich weiß, wie nützlich dies für mich ist, ich bin froh, dass es Ihnen gefällt :)
Mahmoud Zalt
1
Ich wünschte, Sie wissen, dass Sie ein Retter sind
Chay22
1
Das ist eine großartige Antwort.
Caro
1
wie man eine Beziehung aktualisiert. Du hast erklärt, wie man hinzufügt. Könnten Sie bitte auch das Update erklären? Gibt es eine Methode, um solche Datensätze zu aktualisieren updateMany? danke
Hamidreza
3

syncWithoutDetaching([$id_one, $id_two, $id_three]);ist das, wonach Sie suchen. Eigentlich macht es genau das, was [ syncmit dem 2. Parameter false] macht!

Moslemischer Deris
quelle
0

Die syncFunktion löscht die bestehenden Beziehungen und macht Ihr Array zur gesamten Liste der Beziehungen. Sie möchten attachstattdessen Beziehungen hinzufügen, ohne andere zu entfernen.

ceejayoz
quelle
Ich kann attach nicht verwenden, da ich diesen Code in der Update-Methode verwende. Die Geschichte ist, dass der Administrator die Aufgabe aktualisieren und die Eingabeteilnehmer [] mit Benutzern füllen kann, die an der Aufgabe teilnehmen werden. Also muss ich überprüfen, ob es existiert und löschen (oder keinen neuen Datensatz hinzufügen) oder ob es nicht existiert, hinzufügen.
SuperManSL