如何在我的模型中通過關系表多對多改進搜索?

[英]How to Improve search by relation table many-to-many in my model?


Just for simplify my problem, let's say i have a project for a library system that implements all features for borrow, count, search, and add books in my library.

為了簡化我的問題,假設我有一個圖書館系統項目,它實現了借閱,計數,搜索和在我的圖書館中添加圖書的所有功能。

For that project i made 3 main tables: person (id, name, etc), loan (id, id_person, dates, etc) and, of course, book (id, title, etc).

對於該項目,我制作了3個主要表:人(id,姓名等),貸款(id,id_person,日期等),當然還有書(id,title等)。

Since a Person can borrow more than one book at same time, i also needed another table just to link this many-to-many relationship. rel_loan_book (id, id_book, id_loan).

由於一個人可以同時借閱多本書,我還需要另一張表來鏈接這種多對多的關系。 rel_loan_book(id,id_book,id_loan)。

Now, in my Book View i have a Gridview with all information of the book and a column saying whether the book is available for borrow or not (not being used at the moment).

現在,在我的Book View中,我有一個Gridview,其中包含該書的所有信息以及一個列,說明該書是否可以借用(目前尚未使用)。

Here is what i'm doing at the moment:

這就是我現在正在做的事情:

View:

視圖:

[
    'attribute' => 'isAvaliable',
    'value' => function($model) {
        return $model->currentLoan ? 'No' :'Yes';
    },
    'filter' => Html::activeDropDownList($searchModel, 'isAvaliable', ['1' => 'Yes', '0' => 'No'],
        ['class'=>'form-control','prompt' => '']
    )
],

Model Book:

型號書:

public function getCurrentLoan()
{
     return $this->hasOne(Loan::className(), ['id' => 'id_loan'])
         ->viaTable(RelLoanBook::tableName(), ['id_book' => 'id'])
         ->onCondition(['loan.status' => 'A']);
}

Status 'A' in Loan table means it's still active (the book didn't came back).

貸款表中的狀態“A”表示它仍然有效(該書沒有回來)。

My problem is when i try to make a search by available or not available books... At the moment, i'm doing another query just to check what are the borrowed books and then removing (or filtering by) this ids in my search:

我的問題是當我嘗試通過可用或不可用的書籍進行搜索時...目前,我正在進行另一個查詢,只是為了檢查借來的書籍是什么,然后在我的搜索中刪除(或過濾)此ID :

BookSearch:

的BookSearch:

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]);
        }
    }

    ...
}

I don't think this is the best approach for that. But i can't think in a sql query making that search without a subquery:

我不認為這是最好的方法。但我不能在沒有子查詢的情況下在sql查詢中進行搜索:

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' */)

1 个解决方案

#1


0  

First off, do you have a reason for not making loan the junction table? This seems more logical to me and would simplify your query.

首先,你有沒有理由不貸款聯絡表?這對我來說似乎更合乎邏輯,並且會簡化您的查詢。

I.e.:

即:

  • person(id, name)
  • 人(身份證,姓名)
  • book(id, name, author, isbn, publisher, genre, tags)
  • 書(id,name,author,isbn,publisher,genre,tags)
  • loan(id, person_id, book_id, start_date, due_date, return_date, status)
  • loan(id,person_id,book_id,start_date,due_date,return_date,status)

By connecting book and loan the system is more flexible, allowing for:

通過連接賬簿和貸款,系統更加靈活,允許:

  • loan extensions on some of the titles picked up
  • 一些標題的貸款延期被提升
  • early returns for some of the items
  • 一些項目的早期回報

It would be weird if a library would refuse the return of all books if you forgot one of them. That only happens when they are all connected to a single loan.

如果你忘了其中一本書,如果圖書館拒絕歸還所有書籍,那就太奇怪了。只有當它們都連接到一筆貸款時才會發生這種情況。

After a little structural revision, add this to book model:

稍作結構修改后,將其添加到圖書模型中:

public function getIsAvailable()
{
    return !Loan::find()->where([
        'book_id' => $this->id,
        'status' => 'A'
    ])->exists();
}

If a loan record with an active status and this book id exists, then its not available.

如果存在具有活動狀態和此書ID的貸款記錄,則其不可用。

Add isAvailable attribute to the search filter:

將isAvailable屬性添加到搜索過濾器:

 $query->andFilterWhere([
     ...
     'isAvailable' => $this->isAvailable,
 ]);

Links the getIsAvailable function with the dropdown filter.

將getIsAvailable函數與下拉過濾器鏈接。

Adjust isAvailable column in book-view:

在book-view中調整isAvailable列:

[
    'attribute' => 'isAvailable',
    'value' => function($model) {
        return $model->isAvailable ? 'Yes' :'No';
    },
    'filter' => Html::activeDropDownList($searchModel, 'isAvailable', 
        [0 => 'No', 1 => 'Yes'],
        ['class'=>'form-control','prompt' => '']
    )
],

注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2016/03/23/7903458ae84dc2439d4a47a65e58c446.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com