yii2 在 ActiveDataProvider 中组合来自多个查询的数据

yii2 combine data from multiple queries in ActiveDataProvider

我正在尝试将来自不同查询的数据合并到一个活动记录中以进行分页

我有两个不同的数据库table,即

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

从上面我必须为每个查询和 return 数据分别创建多个 activeDataProvider。是否可以将两个查询组合或添加到单个 ActiveDataProvider 而不必为每个查询创建每个数据提供者

有 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() 方法以允许使用两个查询。

资源

如何为 yii2 dataprovider 合并数据还有一个选项。使用 MySql VIEWS

如果两个数据库位于同一台 mysql 服务器上,则可以为来自不同数据库的两个 table 创建一个视图。

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';
    }

并从单独的 table...

中进行选择

Remember that if you create a view inside the first database, then this connection must be used to access the view. You can create the same views in both databases.

有关 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