CakePHP 3.x - hasMany通过关联 - 查找

时间:2015-07-27 01:54:20

标签: cakephp cakephp-3.0

假设我在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']);

这不起作用。我该怎么写呢?

2 个答案:

答案 0 :(得分:16)

通常您使用matching,但ORM似乎不支持在联接表"协会"上匹配,因为它们不是"真实" 34;那时的关联(你可能想要suggest that as an enhancement),它们将在稍后添加。

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

这将使用students别名加入courses_students表格和CourseMemberships联接表格,例如

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)
)

这可能会更有效率,因为它需要较少的选择。

答案 1 :(得分:0)

public partial class PrintTasks: System.Web.UI.Page { public BindingList<SuperObject> mySuperObjectList = new BindingList<SuperObject>(); protected void Page_Load(object sender, EventArgs e) { var myObject = new SuperObject(); myObject.Name = "I"; myObject.Destination = "Love"; myObject.ActionName = "StackOverFlow"; mySuperObjectList.Add(myObject); //What next? } } 允许您提供要在连接表上使用的Table实例的名称,或者提供实例本身。这样可以自定义连接表键,并允许您自定义数据透视表的行为。

使用数组语法定义更具体的关系:

through

请确保您拥有表格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', ]); } } coursesstudents

现在运行代码:

course_memberships

好吧,如果你真的需要与HasMany Associations相关的东西,我很害怕。