Yii2 ActiveRecord нужна помощь по связям
Yii2 ActiveRecord нужна помощь по связям
Имеются таблицы, в которых в БД нет связей и проставить их там не получится.
Вопрос: могу ли я в коде класса от ActiveRecord как-то "силой" прописать их? Чтобы можно было добавить и нормально использовать методы hasOne/hasMany.
Спасибо заранее за ответы.
Вопрос: могу ли я в коде класса от ActiveRecord как-то "силой" прописать их? Чтобы можно было добавить и нормально использовать методы hasOne/hasMany.
Спасибо заранее за ответы.
-
- Сообщения: 910
- Зарегистрирован: 2019.08.13, 01:49
Re: Yii2 ActiveRecord нужна помощь по связям
В основной таблице должен быть первичный ключ. А так, можете прописать связь вручную.
Re: Yii2 ActiveRecord нужна помощь по связям
А где именно их прописывать? Возможно есть пример как это примерно должно выглядеть?yiiliveext писал(а): ↑2020.03.06, 11:14 В основной таблице должен быть первичный ключ. А так, можете прописать связь вручную.
Если имеется ввиду миграция, то не вариант. Нужно именно в рантайме проставить их.
UPD: в основной таблице нет PK. Проектировал БД не я. По-этому и сложности сейчас. Переписываю проект, но в БД ничего менять нельхя, так как первое время будет ходить старый туда.
-
- Сообщения: 910
- Зарегистрирован: 2019.08.13, 01:49
Re: Yii2 ActiveRecord нужна помощь по связям
Что значит в рантайме? Связи прописываются в коде класса ActiveRecord (вашей модели)alexchep писал(а): ↑2020.03.06, 11:26А где именно их прописывать? Возможно есть пример как это примерно должно выглядеть?yiiliveext писал(а): ↑2020.03.06, 11:14 В основной таблице должен быть первичный ключ. А так, можете прописать связь вручную.
Если имеется ввиду миграция, то не вариант. Нужно именно в рантайме проставить их.
Код: Выделить всё
// model Student
public function getRatings()
{
return $this->hasMany(Rating::className(), ['student_id' => 'id']);
}
Код: Выделить всё
//model Rating
public function getStudent()
{
return $this->hasOne(Student::className(), ['id' => 'student_id']);
}
Re: Yii2 ActiveRecord нужна помощь по связям
Это понятно. Но если нет PK. И нет связи таблиц явных в БД. То эти методы не сработают. Будет ругаться, что не может найти связь. Вот я хочу узнать, можно ли каким-то способом игнорить это и говорить с кода, что вот у тебя будет такой PK, и свяжись с той таблицей. Но без миграции. Чтобы ничего не менялось в БД. То есть это будет происходить в рантайме, когда приложение запуститься. Есть варианты ?Что значит в рантайме? Связи прописываются в коде класса ActiveRecord (вашей модели)Код: Выделить всё
// model Student public function getRatings() { return $this->hasMany(Rating::className(), ['student_id' => 'id']); }
Код: Выделить всё
//model Rating public function getStudent() { return $this->hasOne(Student::className(), ['id' => 'student_id']); }
-
- Сообщения: 910
- Зарегистрирован: 2019.08.13, 01:49
Re: Yii2 ActiveRecord нужна помощь по связям
Без PK в основной таблице из коробки не выйдет сделать. Хотя, надо глянуть, я точно не помню как там сделано внутри классов AR.
Посмотрел, там это публичный метод, PK можно прямо в модели задать.
Посмотрел, там это публичный метод, PK можно прямо в модели задать.
Код: Выделить всё
//model Student
public static function primaryKey()
{
return ['id'];
}
-
- Сообщения: 910
- Зарегистрирован: 2019.08.13, 01:49
Re: Yii2 ActiveRecord нужна помощь по связям
При формировании запроса создаваемого с помощью hasOne/hasMany проверяется наличие первичного ключа.
Если его нет, то все, hasOne/hasMany не будет работать
Для того чтобы добиться такого же поведения и использования, я сделал простенький трейт, который и подмешиваю
Код: Выделить всё
/**
* Трейт позволяет создавать произвольные проперти заполнямые вызовом метода класса
* Стандартный механизм ограничен созданием отношений с помощью hasOne hasMany
*
* Класс обязан объявить массив
* protected static $dynamicProps = [...]
* ключ - имя проперти
* значение - имя метода. метод может вернуть ActiveQuery, тогда будет вызван ->all()
*
* @author skynin
*/
trait DynamicPropsTrait
{
private $_dynamicProps = [];
public function __get($name)
{
if (key_exists($name, self::$dynamicProps)) {
if (empty($this->_dynamicProps[$name])) {
$queryMethodName = self::$dynamicProps[$name];
$query = $this->$queryMethodName();
$this->_dynamicProps[$name] = $query instanceof \yii\db\ActiveQuery ? ($query->all()) : $query; // если нужен one() то расширить конфигурирование $dynamicProps
}
return $this->_dynamicProps[$name];
}
return parent::__get($name);
}
public function __set($name, $value)
{
if (key_exists($name, self::$dynamicProps)) {
$this->_dynamicProps[$name] = $value;
return;
}
parent::__set($name, $value);
}
public function __unset($name)
{
if (key_exists($name, self::$dynamicProps)) {
unset($this->_dynamicProps[$name]);
return;
}
parent::__unset($name);
}
public function __isset($name): bool
{
return key_exists($name, self::$dynamicProps) || parent::__isset($name);
}
}
Код: Выделить всё
/*
* @property SmanAR[] $smen
*/
class SportMatchAR ....
{
use DynamicPropsTrait;
protected static $dynamicProps = [
'smen' => 'getSmen',
];
public function getSmen()
{
return SmanAR::find()->andWhere(/*что нужно*/);
}
}
// и далее как обычно
$matchSmen= $spotMatch->smen;
Не желайте странного, и не будет у вас головной боли чтобы достичь этого странного.
Тем более что окажется что оно вам и не нужно было, странное это.
Тем более что окажется что оно вам и не нужно было, странное это.
-
- Сообщения: 910
- Зарегистрирован: 2019.08.13, 01:49
Re: Yii2 ActiveRecord нужна помощь по связям
Ручное задание первичного ключа решает эту проблему.
Оно не будет работать с тем же with и joinWith.Для того чтобы добиться такого же поведения и использования, я сделал простенький трейт, который и подмешиваю
Re: Yii2 ActiveRecord нужна помощь по связям
Связи бывают гораздо хитрее, например с выборками по актуальности итогов
И то что у записи есть первичный ключ - никак не помогает.
То есть связи из бизнес-логики не всегда можно реализовать с помощью PK.
Хотя на уровне реляционных отношений они очевидны и естественны. И сами запросы - эффективны в выполнении.
совершенно верно - именно с этими исключительными полями в ActiveRecord - не будет. Как я понял по коду, именно ради этого так жестко и работают hasOne, hasMany - только с PKОно не будет работать с тем же with и joinWith.
Но обычно то - и не надо.
Решение было как временное, но стало вечным потому что вот как-то не понадобилось еще использовать такое поле в with и joinWith
Но, если вот никак без них, для таких полей в AR - тогда все просто - есть исходники Yii2, наследуйте цепочку объектов ORMа, расширяйте - дописывайте ядро короче
Не желайте странного, и не будет у вас головной боли чтобы достичь этого странного.
Тем более что окажется что оно вам и не нужно было, странное это.
Тем более что окажется что оно вам и не нужно было, странное это.
-
- Сообщения: 910
- Зарегистрирован: 2019.08.13, 01:49
Re: Yii2 ActiveRecord нужна помощь по связям
Я не думаю, что у ТС там какие-то мега-хитрые связи. Он просто спросил как ему сделать обычные hasOne()/hasMany() если у него нет ключей в таблицах. В этом случае решение с заданием первичного ключа вручную является самым простым и валидным.skynin писал(а): ↑2020.03.06, 12:31 Связи бывают гораздо хитрее, например с выборками по актуальности итогов
И то что у записи есть первичный ключ - никак не помогает.
То есть связи из бизнес-логики не всегда можно реализовать с помощью PK.
Хотя на уровне реляционных отношений они очевидны и естественны. И сами запросы - эффективны в выполнении.
Re: Yii2 ActiveRecord нужна помощь по связям
Я поделился тем чем пользуюсь несколько лет. Проблем не было.yiiliveext писал(а): ↑2020.03.06, 12:46 Он просто спросил как ему сделать обычные hasOne()/hasMany() если у него нет ключей в таблицах. В этом случае решение с заданием первичного ключа вручную является самым простым и валидным.
Топикастер пусть и решает, какой способ ему самый простой и валидный.
Не желайте странного, и не будет у вас головной боли чтобы достичь этого странного.
Тем более что окажется что оно вам и не нужно было, странное это.
Тем более что окажется что оно вам и не нужно было, странное это.
Re: Yii2 ActiveRecord нужна помощь по связям
Спасибо за ответы. Буду пробовать.