Php 四对多关系,有口才
我正在使用Laravels雄辩的ORM,我遇到了一个特殊关系的小问题。假设我有下表:Php 四对多关系,有口才,php,laravel,laravel-4,relationship,eloquent,Php,Laravel,Laravel 4,Relationship,Eloquent,我正在使用Laravels雄辩的ORM,我遇到了一个特殊关系的小问题。假设我有下表: Recipe: id | ... | ingredient1 | ingredient2 | ingredient3 | ingredient4 每个配方都有4种配料,我从外部来源以这种特定格式获取数据,这就是为什么我将配料作为列,而不是正常的多对多关系 我可以将这些设置为4个一对多关系,但我希望能够编写$component->usedincipes()->get() 对于4个一对多关系,我必须编写$c
Recipe:
id | ... | ingredient1 | ingredient2 | ingredient3 | ingredient4
每个配方都有4种配料,我从外部来源以这种特定格式获取数据,这就是为什么我将配料作为列,而不是正常的多对多关系
我可以将这些设置为4个一对多关系,但我希望能够编写$component->usedincipes()->get()
对于4个一对多关系,我必须编写
$component->usedincipesasingredient1()->get()
,[…],$component->usedincipesasingredient4()->get()
,然后合并它们,这将导致4个查询
如果您知道在查询数据库之前加入这些的好方法,或者知道如何使4对多关系工作,请回答 从这个问题上,我无法判断您是否已经尝试过这样做,尽管在我看来,您只需要使用单个多对多关系 每个成分大概都有一组共同的属性,可以在一个表中处理所有这些属性
id name created_at updated_at
1 Paprika 01/01/1970 00:00:00 01/01/1970 00:00:00
1 Rosemary 01/01/1970 00:00:00 01/01/1970 00:00:00
1 Basil 01/01/1970 00:00:00 01/01/1970 00:00:00
1 Oregano 01/01/1970 00:00:00 01/01/1970 00:00:00
然后是你的食谱
表格
id name created_at updated_at
1 Herb Soup 01/01/1970 00:00:00 01/01/1970 00:00:00
要保存这些关系,请使用数据透视表component\u recipe
id recipe_id ingredient_id
1 1 1
2 1 2
3 1 3
4 1 4
现在,您所需要的是在您的配方
和配料
模型上建立一个属于“口香糖”的关系
public function scopeGetWithIngredients($query)
{
$query->leftJoin('ingredients i1', 'recipes.ingredient_1', '=', 'i1.id')
->leftJoin('ingredients i2', 'recipes.ingredient_2', '=', 'i2.id')
->leftJoin('ingredients i3', 'recipes.ingredient_3', '=', 'i3.id')
->leftJoin('ingredients i4', 'recipes.ingredient_4', '=', 'i4.id')
->select('recipes.name', 'i1.name AS ing_1', 'i2.name AS ing_2');
}
您可以编写保护代码,以确保一个配方与配料之间只有4种关系,但前提是要保持简单:
Recipe::with('ingredients')->get();
将检索所有配料以及配方
不带枢轴
如果在配方
表中保留列成分_1
、成分_2
等,则可以将类似内容添加到配方
模型中
public function scopeGetWithIngredients($query)
{
$query->leftJoin('ingredients i1', 'recipes.ingredient_1', '=', 'i1.id')
->leftJoin('ingredients i2', 'recipes.ingredient_2', '=', 'i2.id')
->leftJoin('ingredients i3', 'recipes.ingredient_3', '=', 'i3.id')
->leftJoin('ingredients i4', 'recipes.ingredient_4', '=', 'i4.id')
->select('recipes.name', 'i1.name AS ing_1', 'i2.name AS ing_2');
}
然后,你就可以在你的模型中使用
Recipe::getWithIngredients();
我找到了一个似乎在我所有用例中都有效的解决方案
在配方模型中,我将4种成分定义为一对多关系,并创建了两个辅助作用域函数
class Recipe extends Eloquent {
public function ingredient1()
{ return $this->belongsTo('Ingredient', 'ingredient1'); }
public function ingredient2()
{ return $this->belongsTo('Ingredient', 'ingredient2'); }
public function ingredient3()
{ return $this->belongsTo('Ingredient', 'ingredient3'); }
public function ingredient4()
{ return $this->belongsTo('Ingredient', 'ingredient4'); }
public function scopeHasIngredient( $query, Ingredient $ingredient ) {
return $query-> where( 'ingredient1', '=', $ingredient->id )
->orWhere( 'ingredient2', '=', $ingredient->id )
->orWhere( 'ingredient3', '=', $ingredient->id )
->orWhere( 'ingredient4', '=', $ingredient->id );
}
public function scopeWithIngredients( $query ) {
return $query->with('ingredient1', 'ingredient2',
'ingredient3', 'ingredient4');
}
}
class Ingredient extends Eloquent {
public function ingredientForRecipes() {
return Recipe::hasIngredient( $this )->withIngredients();
}
}
要获取一种配料的所有配方,我现在可以调用$component->ingredientForRecipes()->get()
,无需额外查询即可使用这些配料。是的,我可以这样做,但我正在寻找一个没有透视表的解决方案,因为其他一些项目访问相同的数据库。如果没有一个好的解决方案,我将使用透视表并调整其他项目。@darthmaim好的,很公平。我仍然会亲自走这条支点路线,因为它感觉更正常。我说我添加了一种未经测试的方法,你可以在你的模型上使用fluent连接和作用域方法来获取成分。太棒了,我会尝试一下。