2012-10-31 34 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