Nur um mein Problem zu vereinfachen, sagen wir, ich habe ein Projekt für ein Bibliothekssystem, das alle Funktionen zum Ausleihen, Zählen, Suchen und Hinzufügen von Büchern in meiner Bibliothek implementiert. Für dieses Projekt habe ich 3 Haupttabellen gemacht: person (id, name, etc)
, loan (id, id_person, dates, etc)
und natürlich book (id, title, etc)
.Wie verbessert man die Suche nach relation table viele-zu-viele in meinem Modell?
Da eine Person mehr als ein Buch zur gleichen Zeit ausleihen kann, brauchte ich auch eine andere Tabelle, nur um diese Viele-zu-Viele-Beziehung zu verknüpfen. rel_loan_book (id, id_book, id_loan)
.
Jetzt, in meiner Buchansicht habe ich eine Gridview
mit allen Informationen des Buches und einer Spalte, die sagt, ob das Buch zum Ausleihen verfügbar ist oder nicht (wird derzeit nicht verwendet). Hier
ist, was ich im Moment mache:
Ausblick:
[
'attribute' => 'isAvaliable',
'value' => function($model) {
return $model->currentLoan ? 'No' :'Yes';
},
'filter' => Html::activeDropDownList($searchModel, 'isAvaliable', ['1' => 'Yes', '0' => 'No'],
['class'=>'form-control','prompt' => '']
)
],
Modell Buch:
public function getCurrentLoan()
{
return $this->hasOne(Loan::className(), ['id' => 'id_loan'])
->viaTable(RelLoanBook::tableName(), ['id_book' => 'id'])
->onCondition(['loan.status' => 'A']);
}
Der Status 'A'
in Loan Tabelle bedeutet, es ist nach wie vor aktiv (das Buch kam nicht zurück).
Mein Problem ist, wenn ich versuche, nach verfügbaren oder nicht verfügbaren Bücher zu suchen ... Im Moment mache ich eine andere Abfrage, nur um zu überprüfen, was die geliehenen Bücher sind und dann entfernen (oder filtern) ids in meiner Suche:
Buchsuche:
public $isAvaliable;
...
public function rules()
{
return [
[['isAvaliable'], 'safe'],
];
}
...
public function search($params)
{
...
if ($this->isAvaliable !== '') {
$subQuery = Book::find()->select('book.id');
$subQuery->joinWith(['currentLoan'])
->andWhere(['is not' , 'loan.id', null])
->all();
if ($this->isAvaliable === '1') {
$query->andWhere(['not in', 'book.id', $subQuery]);
} elseif ($this->isAvaliable === '0') {
$query->andWhere(['in', 'book.id', $subQuery]);
}
}
...
}
ich glaube nicht, dies ist der beste Ansatz für das ist. Aber ich kann in einer SQL-Abfrage nicht denken, dass die Suche machen, ohne eine Unterabfrage:
SELECT * FROM book
LEFT JOIN rel_loan_book ON rel_loan_book.book_id = book.id
LEFT JOIN loan ON loan.id = rel_loan_book.loan.id
WHERE (/* my filters */)
AND (/* some restriction that check if the book does OR does not have a loan with status === 'A' */)
Zunächst einmal, ich danke Ihnen für die Beantwortung und sorry letztere Antwort. Also, wie ich in meiner Frage festgestellt habe, habe ich eine ** viele-zu-viele ** Beziehung. Ein Darlehen kann mehr als ein Buch enthalten. Außerdem sieht es gut aus, aber das bedeutet, dass ich für jedes Buch in meiner Gridview eine SQL-Abfrage erzeuge, die diese Prüfung durchführt. Meine ursprüngliche Abfrage machte das in einer einzigen Suche, aber ich wollte das ohne Unterabfrage machen. Im Moment bin ich schon weiter, aber ich werde diese Frage offen lassen, in der Hoffnung auf neue Lösungen oder wenn ich welche finde. – Clyff
Wenn Sie eines der Bücher, die Sie abgeholt haben, fertiggestellt haben und es zurückgeben (die anderen zu Hause lassen), während Sie einige andere abholen, reicht Ihr Schema nicht aus. Sie könnten der Buch-Tabelle die Spalte isAvailable hinzufügen und den Wert anpassen, wenn ein Buch abgeholt/zurückgeholt wird. Andernfalls benötigen Sie eine Unterabfrage. – ttdijkstra
Ich sehe Ihren Punkt, aber das aktuelle Szenario sieht nicht so aus. Wir können einen Teil der ausgeliehenen Gegenstände nicht zurückgeben. Tut mir leid, aber ich benutzte ein Beispiel einer Bibliothek, nur um mich besser zu erklären, wie ich in meiner Frage sagte. In einem echten Bibliotheksprojekt ist Ihr Ansatz richtig. – Clyff