yii2 объединяет данные из нескольких запросов в ActiveDataProvider - PullRequest
1 голос
/ 24 октября 2019

Я пытаюсь объединить данные из разных запросов в одну активную запись с целью разбивки на страницы.

У меня есть две разные базы данных с похожей таблицей, то есть

db1
  tbl_products
   id,quantity,price

Сейчас на db2

db2
 tbl_products
  id,quantity,price

Итак, у меня есть две модели с разными подключениями, где первая модель подключается к db1, а вторая к db2

class ProductsDb1 extends ActiveRecord{
   public static function getDb()
    {
      return 'db1'
    }
}

class ProductsDb2 extends ActiveRecord{
   public static function getDb()
    {
      return 'db2'
    }
}

Так что теперь в моем текущем запросе у меня есть

$db1productsQuery = ProductsDb1::find()->where(...)
$db2productsQuery = ProductsDb2::find()->where(...);

На моем ActiveDataProvider я передаю свой запрос как

     $data = new ActiveDataProvider([
          'query' => $db1productsQuery, //pass the dbproducts query
           'sort' => ['defaultOrder' => ['quantity' => SORT_DESC]],
            'pagination' => [
               'pageSize' => $arr['perPage'],
                  'page' => $arr['page']
              ],
            ]);

. Как указано выше, мне нужно создать несколько activeDataProviders для каждого запроса и возвращать данные отдельно. Можно ли объединить или добавить оба запроса в один ActiveDataProvider, вместо того чтобы создавать каждый поставщик данных для каждого запроса

Ответы [ 2 ]

1 голос
/ 24 октября 2019

Есть 3 варианта, как с этим справиться.

1) UNION на двух БД

Для этого обе ваши БД должны быть на одном сервере, и ваш пользователь БД должен быть предоставленпривилегии для доступа к обеим БД.

$query = ProductsDb1::find()
    ->select(['id', 'quantity', 'price']);
$subquery = (new \yii\db\Query())
    ->select(['id', 'quantity', 'price'])
    ->from('secondDb.products');
$query->union($subquery, true);
$dp = new \yii\data\ActiveDataProvider([
    'query' => $query
]);

2) ArrayDataProvider

Вы можете использовать \yii\data\ArrayDataProvider вместо \yii\data\ActiveDataProvider.

$products1 = ProductsDb1::find()
    ->select(['id', 'quantity', 'price'])
    ->all();

$products2 = ProductsDb2::find()
    ->select(['id', 'quantity', 'price'])
    ->all();
$dp = new \yii\data\ArrayDataProvider([
    'allModels' => array_merge($products1, $products2),
])

3) Реализовать свои собственныепоставщик данных

Эта опция наиболее сложна. Но если вы не соответствуете ограничению первого варианта, и у вас слишком много продуктов для использования второго варианта, вы должны использовать этот параметр. Вы можете расширить \yii\data\ActiveDataProvider и переопределить его методы prepareTotalCount() и prepareModels(), чтобы разрешить использование двух запросов.

Ресурсы

0 голосов
/ 24 октября 2019

Существует еще один вариант объединения данных для провайдера данных yii2. Использование MySql VIEWS .

Если две базы данных расположены на одном и том же сервере MySQL, то можно создать одно представление для двух таблиц из разных баз данных.

CREATE VIEW union_products AS 
SELECT db1.id, db1.quantity, db1.price FROM db1.tbl_products as db1 
UNION 
SELECT db2.id, db2.quantity, db2.price FROM db2.tbl_products as db2

Можно добавить псевдонимы к именам столбцов, например db1.id as db1_id и т. Д. Затем создайте модель Active Record с именем, совпадающим с именем представления:

class UnionProducts extends \yii\db\ActiveRecord
{
    public static function getDb()
    {
        // using connection "db2"
        return \Yii::$app->db2;  
    }

    public static function tableName()
    {
       return 'union_products';
    }

И сделайте выбор из отдельной таблицы ...

Помните, что если высоздайте представление внутри первой базы данных, затем это соединение должно использоваться для доступа к представлению. Вы можете создавать одинаковые представления в обеих базах данных.

Для получения дополнительной информации о MySql VIEWS, пожалуйста, прочитайте https://dev.mysql.com/doc/refman/8.0/en/views.html

Чтобы показать все представления на сервере MySQL, запустите sql:

SELECT TABLE_SCHEMA, TABLE_NAME 
FROM information_schema.tables 
WHERE TABLE_TYPE LIKE 'VIEW';

При необходимости удалить вид:

DROP VIEW IF EXISTS db1.your_view
...