簡體   English   中英

CakePHP 3.x - hasMany通過關聯 - 查找

[英]CakePHP 3.x - hasMany through association - find

假設我在CookBook中有完整的設置: http//book.cakephp.org/3.0/en/orm/associations.html

class StudentsTable extends Table
{
    public function initialize(array $config)
    {
        $this->belongsToMany('Courses', [
            'through' => 'CourseMemberships',
        ]);
    }
}

class CoursesTable extends Table
{
    public function initialize(array $config)
    {
        $this->belongsToMany('Students', [
            'through' => 'CourseMemberships',
        ]);
    }
}

class CoursesMembershipsTable extends Table
{
    public function initialize(array $config)
    {
        $this->belongsTo('Students');
        $this->belongsTo('Courses');
    }
}

Student BelongsToMany Course
Course BelongsToMany Student

id | student_id | course_id | days_attended | grade

我應該如何構建查詢以查找給定學生的課程,他的成績為==“A”?

$query = $this->Courses->find('all')
    ->contain(['CourseMemberships'])
    ->where(['CourseMemberships.student_id' => $student['id'], 'CourseMemberships.grade' => 'A']);

這不行。 我該怎么寫呢?

通常你會使用匹配 ,但是ORM似乎不支持在連接表“關聯”上匹配,因為它們在那時不是“真正的”關聯(你可能想建議作為增強 ),它們正在稍后補充道。

matching()變通方法

什么工作是在外部查詢上使用matching()where() ,即

$query = $this->Courses
    ->find('all')

     // contain needs to use `Students` instead (the `CourseMemberships`
     // data can be found in the `_joinData` property of the tag),
     // or dropped alltogether in case you don't actually need that
     // data in your results
    ->contain(['Students'])

     // this will do the magic
    ->matching('Students')

    ->where([
        'CourseMemberships.student_id' => $student['id'],
        'CourseMemberships.grade' => 'A'
    ]);

這將使用CourseMemberships別名加入students表以及courses_students連接表,例如

INNER JOIN
    students Students ON 1 = 1
INNER JOIN
    courses_students CourseMemberships ON (
        Courses.id = (CourseMemberships.course_id)
        AND Students.id = (CourseMemberships.student_id)
    )

因此可以應用條件。 這感覺就像一個不太好的解決方法。

使用額外的關聯(可能是更好的方法)

另一種選擇是添加另一個顯式關聯(如提到的@AtaboyJosef),即連接表的hasMany關聯(這將在稍后的時間點自動完成,但如前所述, matching()為時已晚)。

請注意,這將要求將連接表命名為course_memberships

class CoursesTable extends Table
{
    public function initialize(array $config)
    {
        $this->belongsToMany('Students', [
            'joinTable' => 'course_memberships',
            'through' => 'CourseMemberships',
        ]);

        $this->hasMany('CourseMemberships', [
            'foreignKey' => 'course_id'
        ]);
    }
}

這樣您就可以在CourseMemberships關聯上使用匹配

$query = $this->Courses
    ->find('all')
    // with this solution you can also use contain for `CourseMemberships`
    ->contain(['CourseMemberships'])
    ->matching('CourseMemberships', function(\Cake\ORM\Query $query) use ($student) {
        return $query->where([
            'CourseMemberships.student_id' => $student['id'],
            'CourseMemberships.grade' => 'A'
        ]);
    });

應該創建一個類似的查詢

INNER JOIN course_memberships CourseMemberships ON (
    CourseMemberships.student_id = 1 
    AND CourseMemberships.grade = 'A' 
    AND Course.id = (CourseMemberships.course_id)
)

這可能會更有效,因為它需要更少的選擇。

through允許您提供要在連接表上使用的Table實例的名稱,或者提供實例本身。 這使得可以自定義連接表鍵,並允許您自定義數據透視表的行為。

使用數組語法定義更具體的關系:

class StudentsTable extends Table
{

    public function initialize(array $config)
    {
        $this->belongsToMany('Courses', [
            'joinTable' => 'courses',
            'through' => 'CourseMemberships',
        ]);
    }
}

class CoursesTable extends Table
{

    public function initialize(array $config)
    {
        $this->belongsToMany('Students', [
            'joinTable' => 'students',
            'through' => 'CourseMemberships',
        ]);
    }
}

class CoursesMembershipsTable extends Table
{

    public function initialize(array $config)
    {
        $this->belongsTo('Students', [
            'foreignKey' => 'student_id',
            'joinType' => 'INNER',        // OR specify the type 
        ]);
        $this->belongsTo('Courses', [
            'foreignKey' => 'course_id',
            'joinType' => 'INNER',
        ]);
    }
}

確保你有表coursesstudentscourse_memberships

現在運行代碼:

$query = $this->Courses->find('all')
    ->contain(['CourseMemberships'])
    ->where(['CourseMemberships.student_id' => $student['id'], 'CourseMemberships.grade' => 'A']);

好吧,如果你真的需要與HasMany Associations有關的東西,我很害怕。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM