Eloquent hasMany с внешним ключом на объединенном столе

Предположим это:

class List extends Model
{
    public function items(){
        return $this->hasMany(Items::class, 'c.class_id', 'class_id')
            ->rightjoin('items_classes as c', 'c.items_id', '=', 'items.id');
    }
}

Проблема в том, что Eloquent добавляет items к полю внешнего ключа, и окончательный запрос:

SELECT * FROM items
RIGHT JOIN items_classes as c ON c.items_id = items.id
// here it is
WHERE items.c.class_id = 10

Даже использование DB::raw('c.class_id') не решило проблему.


person Omid    schedule 20.02.2019    source источник
comment
Как выглядит код построения вашего запроса? Как вы определяете свой запрос? Кроме того, является ли хорошей практикой правильное соединение в методе отношений?   -  person Fjarlaegur    schedule 20.02.2019
comment
Я согласен с @Fjarlaegur. Не рекомендуется выполнять правильное объединение методов отношений. Вместо этого создайте новый метод, повторно используйте этот метод и прикрепите туда правильное соединение. Кроме того, где написано условие where, которое вы показали?   -  person nice_dev    schedule 20.02.2019
comment
@Fjarlaegur Я действительно понятия не имею, что вы имеете в виду под «Как выглядит код построения вашего запроса?». Запрос генерируется этой функцией отношения.   -  person Omid    schedule 20.02.2019
comment
@ vivek_23 Не могли бы вы дать мне ссылку на любую документацию, посвященную такому решению? Мне нужен пример.   -  person Omid    schedule 20.02.2019
comment
@Omid Для методов, определяющих отношения, к ним не должно быть никаких дополнительных вещей. Это заставит его выполняться каждый раз, когда вызывается items(), даже если иногда в этом нет необходимости. Это сделало бы его тесно связанным. Вместо этого создайте новый метод и присоедините к нему этот метод с помощью правильного соединения. Кроме того, если запрос генерируется самим этим методом, то выполняется какой-то boot() метод, присоединяющий это where условие каждый раз, когда он выполняется. Можете ли вы показать нам этот метод?   -  person nice_dev    schedule 20.02.2019
comment
@vivek_23 Я разместил все, что хочу сделать. Нет никакого дополнительного метода, чтобы показать вам. Также я не собираюсь добавлять дополнительное предложение where к запросу отношений. Это условие where является поведением Eloquent Builder по умолчанию, и мы хотели его изменить. Однако я обнаружил, что это не будет решено, и ядро ​​Laravel нуждается в некоторых изменениях. github.com/laravel/ideas/issues/1528   -  person Omid    schedule 20.02.2019
comment
@Omid This where condition is the default behavior of Eloquent builder Такого никогда не бывает. Laravel определяет только отношения и соответственно включает joins. Вы проверили, есть ли какой-либо метод boot() в любом из определений ваших моделей? Подробнее см. здесь.   -  person nice_dev    schedule 20.02.2019


Ответы (1)


Если вы заметили сигнатуру метода отношения hasMany:

return $this->hasMany(Model::class, 'foreign_key', 'local_key');

Это означает, что когда Laravel сделает запрос, он будет рассматривать второй аргумент foreign_key как столбец table, определенный в Model::class.

Чтобы упростить в вашем случае:

return $this->hasMany(Items::class, 'c.class_id', 'class_id')->...

Оставив на мгновение правое соединение, Laravel рассматривает c.class_id как внешний ключ таблицы Item::class, которая на самом деле является таблицей items.

Таким образом, результирующий запрос:

SELECT * FROM items WHERE items.c.class_id = 10

Затем, когда вы добавляете правильное соединение, laravel просто добавляет в основной запрос и делает это:

SELECT * FROM items
RIGHT JOIN items_classes as c ON c.items_id = items.id
WHERE items.c.class_id = 10

Laravel не будет ссылаться на items_classes в отношении, потому что вы связываете модель List с Item::class, а не с ItemClass::class.

Я не уверен в данных, которые вам нужны, но посмотрите, можете ли вы использовать их, как показано ниже:

class List extends Model
{
    public function items(){
        return $this->hasMany(Items::class, 'c.class_id', 'class_id');
    }

}


List::with(['items', function($q){

    return $q->->rightjoin('items_classes as c', 'c.items_id', '=', 'items.id');
}])->get();

Надеюсь, это даст вам представление о том, как вы можете обновить свои отношения, чтобы получить желаемый запрос. Если вы добавите свою структуру таблицы и данные, которые хотите, я могу обновить ответ с помощью отношений для вас.

person Mihir Bhende    schedule 20.02.2019
comment
Спасибо, что уделили время моей проблеме. Однако я обнаружил, что это все равно не решит, но с переопределением метода hasMany. github.com/laravel/ideas/issues/1528 - person Omid; 25.02.2019