2016-09-28 62 views
0

我有以下表格:Yii2渴望負荷聚集

  • 內容 - ID (PK),標題,...等領域...
  • CONTENT_CATEGORY - CONTENT_ID (FK到內容),CATEGORY_ID (FK到內容)

其中一條內容has_many類別,而類別也是一段內容。

在內容我有以下代碼:

public function getCategories() 
{ 
    return $this 
     ->hasMany(Category::className(), ['id' => 'category_id']) 
     ->viaTable('content_category', ['content_id' => 'id']); 
} 

public function getCategoriesCsv(){ 
    ... 
} 

對於在後端我的網格視圖中,我想顯示逗號分隔的類別列表針對每條內容。

我知道我可以單獨選擇這些信息,但是我希望將它作爲find查詢的一部分,並在可能的情況下使用現有關係。

+2

使用匿名函數獲取gridview的所需值進行優化,以更可愛的狀態。 –

+0

@InsaneSkull,但它會爲每一行運行一個單獨的查詢。 – Arth

+2

不是真的,如果你使用'joinWith()'或'with()'。只是使用循環。如果使用gridview和dataProvider輸出更新問題。我可以搭把手。 –

回答

0

使用類別受壓

本來我實現它:

public function getCategoriesCsv(){ 
    $categoryTitles = []; 
    foreach ($this->categories as $category){ 
     $categoryTitles[] = $category->title; 
    } 
    return implode(', ', $categoryTitles);  
} 

感謝@IStranger,我neatened這:

public function getCategoriesCsv() 
{ 
    $titles = ArrayHelper::getColumn($this->categories, 'title'); 
    return implode(', ', $titles); 
} 

沒有類別的受壓

我現在已經設法通過增加一個獨立的CategoryCsv ActiveRecord的,以避免加載所有的分類模型:

class CategoryCsv extends ActiveRecord 
{ 
    public static function tableName(){ 
    return '{{%content_category}}'; 
    } 

    public function attributes(){ 
    return ['content_id', 'value']; 
    } 

    public static function find(){ 
    return parent::find() 
     ->select([ 
     'content_id', 
     'GROUP_CONCAT(
      categoryCsv.title 
      ORDER BY categoryCsv.title 
      SEPARATOR ", " 
     ) value' 
     ]) 
    ->innerJoin('content categoryCsv','category_id = categoryCsv.id') 
    ->groupBy('content_id'); 
    } 
} 

然後在內容的ActiveRecord:

public function getCategoriesCsv(){ 
    return $this->hasOne(CategoryCsv::className(), ['content_id' => 'id']); 
} 

因此我可以訪問像這樣的值:

$contents = Content::find()->with('categoryCsv')->all(); 
foreach($contents as $content){ 
    echo $content->categoryCsv->value; 
} 
1

使用定義的關係(更簡單,效率更低)。

這種方法的典型方式,它適用於相關的Category模型。因此它需要大量的內存。

class Content extends \yii\db\ActiveRecord 
{ 
    /** 
    * Returns comma separated list of category titles using specified separator. 
    * 
    * @param string $separator 
    * 
    * @return string 
    */ 
    public function getCategoriesCsv($separator = ', ') 
    { 
     $titles = \yii\helpers\ArrayHelper::getColumn($this->categories, 'title'); 

     return implode($separator, $titles); 
    } 

    // ... 
} 

應與預先加載使用:

Content::find() 
    ->with('categories') 
    ->all(); 

使用子查詢(更有效,不太方便)

這種方法使用子查詢和不使用關係和相關模型。因此這種方式更快,並保留大量的內存。

class Content extends \yii\db\ActiveRecord 
{ 

    const ATTR_CATEGORIES_CSV = 'categoriesCsv'; 

    /** 
    * @var string Comma separated list of category titles. 
    */ 
    public $categoriesCsv; 

    /** 
    * Returns DB expression for retrieving related category titles. 
    * 
    * @return \yii\db\Expression 
    */ 
    public function prepareRelatedCategoriesExpression() 
    { 
     // Build subquery that selects all category records related with current content row. 
     $queryRelatedCategories = Category::find() 
      ->leftJoin('{{%content_category}}', '{{%content_category}}.[[category_id]] = {{%category}}.[[id]]') 
      ->andWhere(new \yii\db\Expression('{{%content_category}}.[[content_id]] = {{%content}}.[[id]]')); 

     // Prepare subquery for retrieving only comma-separated titles 
     $queryRelatedCategories 
      ->select(new \yii\db\Expression('GROUP_CONCAT({{%category}}.[[title]])')); 

     // Prepare expression with scalar value from subquery 
     $sqlRelatedCategories = $queryRelatedCategories->createCommand()->getRawSql(); 

     return new \yii\db\Expression('(' . $sqlRelatedCategories . ')'); 
    } 

    // ... 
} 

當附加列的別名等於某些型號的性能,它將被all()方法來填充:

$contentModels = Content::find() 
    ->andSelect([ 
     '*', 
     Content::ATTR_CATEGORIES_CSV => Content::prepareRelatedCategoriesExpression(), 
    ]) 
    ->all(); 


foreach ($contentModels as $contentModel) { 
    $contentModel->id; 
    $contentModel->categoriesCsv; // it will be also populated by ->all() method. 
    // ... 
} 

PS:我沒有測試此代碼,大概應該是固定的查詢檢索類別。

此外,在本例中使用的書面基地簡單的語法,但它可能會使用不同的助手,結款等

+0

更新我的代碼以使用像你的ArrayHelper,非常整潔!謝謝 – Arth