2016-03-23 5 views
1

私の問題を単純化するために、私は私のライブラリ内の借用、カウント、検索、およびブックを追加するためのすべての機能を実装するライブラリシステムのプロジェクトを持っているとしましょう。私のモデルで多対多の関係テーブルによる検索を改善するには?

このプロジェクトでは、person (id, name, etc),loan (id, id_person, dates, etc)、もちろんbook (id, title, etc)の3つのメインテーブルを作成しました。

人は一度に複数の本を借りることができるので、多対多関係をリンクするために別のテーブルも必要でした。 rel_loan_book (id, id_book, id_loan)

私のブックビューでは、本のすべての情報とその本が借用可能かどうか(現時点では使用されていないかどうか)を示す欄を持つGridviewがあります。ここで

は、私は現時点ではやっているものです:

ビュー:

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

モデル帳:ローンテーブルの

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

ステータス'A'が、それはまだだ意味しますアクティブ(本は戻ってこなかった)。

私の問題は、利用可能な書籍または利用できない書籍を検索しようとしたときです...現時点では、私は借用した書籍が何であるかを確認してから、これを削除(またはフィルタリング)するだけです私の検索では、IDS:

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

    ... 
} 

私は、これはそのための最善のアプローチであるとは思いません。しかし、私は、サブクエリなしでその検索を行う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' */) 

答えて

0

まず第一に、あなたはジャンクションテーブルの融資をしていない理由がありますか?これは私にとってもっと論理的で、クエリを簡略化します。

すなわち:

  • 人(ID、名前)
  • ブック(ID、名前、著者、ISBN、出版社、ジャンル、タグ)
  • ローン(ID、PERSON_ID、book_id、START_DATE、

      01:DUE_DATE接続ブックや融資制度により、RETURN_DATE、ステータスが)

    、のために、より柔軟なことができていますタイトルの一部にの

  • ローンの拡張機能は、あなたがそれらのいずれかを忘れてしまった場合、ライブラリは、すべての書籍の返却を拒否するならばそれは奇妙だろう項目

の一部について

  • 早期リターンを拾いました。彼らはすべてが単一のローンに接続されている場合にのみ発生します。少し構造改正後

    、本モデルにこれを追加します。

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

    アクティブ状態と本書IDを持つローンレコードが存在する場合、その利用できません。

    は、検索フィルタにisAvailable属性を追加します。

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

    リンクgetIsAvailable機能をドロップダウンフィルタで。

    がbook-ビューでisAvailable列を調整します。

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

    まず第一に、後者の応答に答えると、申し訳ありませんありがとうございました。だから、私は私の質問で確立したように、私は**多対多関係を持っています。 1つのローンに複数のブックを含めることができます。それに加えて、アプローチは良く見えますが、それは私のgridview内の各書籍について、そのチェックを行うSQLクエリを生成することを意味します。私の元のクエリは、単一の検索でそれを作ったが、私はサブクエリなしでそれを行うために探していた。現時点ではすでに進んでいますが、新しい解決策が必要な場合や、見つけたらこの質問を公開します。 – Clyff

    +0

    あなたが拾い集めた本のうちの1つを完成させ、他のものを手に入れながらそれを返す(他人を家に残す)と、あなたのスキーマは十分ではありません。ブックテーブルにisAvailableカラムを追加して、ブックをピックアップ/戻したときの値を調整することができます。それ以外の場合は、サブクエリが必要です。 – ttdijkstra

    +0

    私はあなたの意見を見ていますが、現在のシナリオはこのようには見えません。借りた物の一部を返すことはできません。申し訳ありませんが、私は私の質問で言ったように、自分自身を説明するためにライブラリの例を使用しました。実際の図書館プロジェクトでは、あなたのアプローチは正しいです。 – Clyff