2012-10-31 41 views
3

我是yii的新手,但是在php和sql方面有很多經驗。 我希望有更多有經驗的人能夠指引我走向正確的方向。我有兩個模型,Project和Costs,它們通過project_cost表在多對多關係中相互關聯。原因是成本可以在項目之間共享。在project_cost表中有一個額外的列,其中包含多少成本分配給特定項目。從yii中的兩個相關模型中檢索兩列的總和

所以項目模型的關係是這樣的,其正在爲讓所有的細節完美的罰款:

class Project extends CActiveRecord 
{ 

    /** 
    * @return array relational rules. 
    */ 
    public function relations() 
    { 
    return array(
     'projectcost' => array(self::HAS_MANY, 'ProjectCost', 'project_id'), 
     'cost'  => array(self::HAS_MANY, 'Cost', array('cost_id'=>'id'),'through'=>'projectcost'), 
     //i.e. a many to many relation of cost through the projectcost model 

     ); 
    } 
    ... 
} 

在成本模型有一個名爲Value列,並在project_cost表有列名百分比。這是很容易構建一個包含一個SQL查詢,讓我總和爲項目成本這樣的功能:

select sum(project_cost.Percent*cost.Value) 
from project_cost join cost on project_cost.cost_id=cost.id 
where project_cost.project_id=1  

,但有沒有辦法通過Yii中關係做?我知道關於STAT關係,但我們不清楚在這種情況下如何應用它們,因爲迄今爲止我所讀到的大部分內容都表明,如果關係中只有兩種模式,那麼關係的效果最好。

+0

更多信息:在現階段,我由具有做到這一點公共函數getProjectsum()在模型中具有相應的公共變量projectsum。這意味着我可以像訪問這些模型的變量那樣訪問這些信息:$ model-> projectsum,但是它不會感覺到,因爲每次訪問模型變量時都會運行sql。 – SiggiSmara

回答

1

您可以創建一個範圍,以抓住這個數據,在你的項目模型像創建方法:

public function withAdjustedCost() 
{ 
    $this->getDbCriteria()->mergeWith(array(
     'with'=>array(
      'projectcost', 
      'cost', 
     ), 
     'select'=>'*, sum(projectcost.Percent*cost.Value) as adjustedCost', 
    )); 

    return $this; 
} 

那麼你應該能夠當你抓你的項目模型中使用這個;

$models = Project::model->withAdjustedCost()->findAll(); 

我沒有測試它,你可能需要用它一點點修補,或可能需要以訪問它定義爲$adjustedCost模型的屬性(然後再次,也許不是)。無論如何,可能是一個方向去。

+0

這可能是什麼,我會玩一下,並報告回來(希望在未來不會太長...) – SiggiSmara

0

您可能想看看CDbCriteria類,它可以允許您使用Yii框架構建查詢,因此「正確」。

此外,我認爲你可以使用CActiveRecord->getRelated()方法來拉出數組中的所有ProjectCost模型,然後使用foreach循環,以便建立你想要的總和。在您的項目模型,你可以非常創建的方法是這樣的:

class Project extends CActiveRecord 
{ 
    ... 
    /** 
    * @return the sum of all weighed Costs corresponding to this Project. 
    */ 
    public function getTotalCost() 
    { 
     $projectCosts = $this->getRelated('projectcost'); // fetches array of ProjectCost models, which you can iterate over 
     $sum = 0; 
     foreach($projectCosts as $projectCost) 
     { 
      $sum += $projectCost->Percent * $projectcost->getRelated('cost')->Value; 
     } 
     return $sum; 
    } 
    ... 
} 

這依賴於以下思路:

$projectcost->getRelated('cost')->Value; 

你ProjectCost模型具有這樣的關係:

'cost' => array(self::HAS_ONE, 'Cost', 'cost_id'), 

它允許getRelated()獲取相關的Cost模型,只要您需要訪問它。

所以你基本上可以簡單地用$model->getTotalCost()來獲得你在查詢中表達的成本總和,但實際上是在模型中構建的,我認爲它是適當的MVC,而不是讓數據庫使用查詢來爲你做計算。

編輯:getRelated()在處理相關記錄時已被證明是真正的朋友,它根據它所處理的關係的性質獲取一組記錄或一條記錄。

由於您對數據庫訪問的關注,您還可以看看CActiveRecord->afterFind(),您可以重載該模型,以便在加載模型後立即計算項目總和並將其設置爲公用變量。所以你有你的代碼,如:

public $projectSum = 0; 
public function afterFind(){ 
    //Fetch array of ProjectCost models, which you can iterate over 
    foreach($this->getRelated('projectcost') as $projectCost) 
    { 
    $this->projectSum += $projectCost->Percent * $projectcost->getRelated('cost')->Value; 
    } 
} 
+0

我沒有看到這個解決方案與冰河(和我)出現的真正區別雖然我喜歡它。每次你想要訪問這些信息時,它仍然會執行一個sql查詢。如果您只處理一個項目,但爲所有項目創建成本彙總和/或搜索成本值可能會很困難,這很好。 – SiggiSmara

+0

只有在模型完成加載時才執行查詢。$ projectSum的用法是隻有一個數據庫訪問權限來加載主要信息並使用它計算這種內在信息,因此避免了單獨查詢的需要,因爲它是存儲在模型中,並且可供使用而無需再次查詢。我只是想知道我擁有模型中需要的所有信息,而無需每次需要時都執行特定的查詢。此外,我認爲該模型可以定製加載這些信息只在某些場景或類似的... – Snivs

0

簡單有效:

$sum = Yii::app()->db->createCommand(" 
    select sum(project_cost.Percent*cost.Value) 
    from project_cost 
    join cost on project_cost.cost_id=cost.id 
    where project_cost.project_id=1 
")->queryScalar(); 

$總和===假,如果有什麼地方錯了

+0

感謝icefront,這就是我目前正在做的:)我想更多的預取這些信息的行在關係中做了什麼。 – SiggiSmara