【问题标题】:yii2 combine data from multiple queries in ActiveDataProvideryii2 在 ActiveDataProvider 中组合来自多个查询的数据
【发布时间】:2020-02-20 11:25:26
【问题描述】:

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

我有两个具有相似表的不同数据库,即

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 而不必为每个查询创建每个数据提供程序

【问题讨论】:

    标签: php yii2 yii2-model yii2-active-records


    【解决方案1】:

    还有一个选项可以为 yii2 dataprovider 合并数据。使用 MySql 视图。

    如果两个数据库位于同一个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
    

    【讨论】:

      【解决方案2】:

      有 3 个选项来处理这个问题。

      1) 跨两个 DB 的 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) 数组数据提供者

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

      资源

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多