将现有记录附加到Eloquent的hasMany/belongsTo关系

4
我有一个模型,其中包含多个。每个属于一个。
class SalesArea extends Model
{
    public function regions() {
        return $this->hasMany('App\Region');
    }
}

class Region extends Model
{
    public function sales_area() {
        return $this->belongsTo('App\SalesArea');
    }
}

由于组织结构的一些变化,在创建区域之后才会创建父级(销售区)。我试图在创建销售区记录时将区域与其关联的销售区相关联。

我创建了一个迁移来将 sales_area_id 添加到 "regions" 表中,并且它们当前都是空的。

我有一个选择框,其中包含不同区域的 ID,并且我希望通过 ID 数组一次性将这些区域与销售区关联起来。但是,没有任何关联方法能够起作用。

$area = SalesArea::create($request->all());

$area->regions()->attach([1,2,3]); // BadMethodCallException with message 'Call to undefined method Illuminate\Database\Query\Builder::attach()

$area->regions()->add([1,2,3]); // BadMethodCallException with message 'Call to undefined method Illuminate\Database\Query\Builder::add()'

$area->regions()->sync([1,2,3]); // BadMethodCallException with message 'Call to undefined method Illuminate\Database\Query\Builder::sync()'

$area->regions()->associate([1,2,3]); // BadMethodCallException with message 'Call to undefined method Illuminate\Database\Query\Builder::associate()'

我对这个应该怎么工作感到困惑。区域已经存在,我只需要将它们与所关联的销售区域建立联系。

“1,2,3”是区域ID吗?据我所知,attach()sync()associate()与“belongs to many”关系有关。你不能在这里使用它们。 - iamab.in
那么在一对多关系中,我可以使用什么呢? - Oranges13
BelongsTo可以使用associate(),HasMany(或HasOne)使用save()。您也可以仅更新外键值,而不必始终使用所述方法。 - Devon
3
为什么不直接使用 Region::whereIn('id', [$ids])->update(['sales_area_id' => $area->id]); - Devon
1
Region::where('id', [array of IDs]); 不会返回 Region 的集合,而是一个 QueryBuilder,所以在 ->saveMany() 中使用它不会有太大作用。必须先使用 ->get()。是的,我确定有一种避免循环的方法,但这只是一个例子。 - Tim Lewis
显示剩余5条评论
2个回答

2
public function store(Request $request)
{
    $this->validate($request, [
       'name' => 'required|unique:sales_areas',
       'regions' => 'required|array',
       'regions.*' => 'int',
    ]);

    $salesArea = SalesArea::create($request->all());

    // Because we have a hasMany not a many to many, we have to do it this way
    Region::whereIn('id', $request->regions)->update(['sales_area_id' => $salesArea->id]);

    flash('Created Sales Area ' . $salesArea->name);
    return redirect()->route('areas.index', $salesArea->id);
}

1
请确保您的regions表中拥有sales_area_id列。
$salesArea = SalesArea::create($request->all());

$regions = Region::whereIn('id', [1, 2, 3])->get();

$salesArea->regions()->saveMany($regions);

我不确定你为什么要以这种方式创建地区。如果SalesArea和Region之间存在hasMany()关系,则所有地区都应该像这样创建:

$salesArea->regions()->create([ ... ]);

如果您的关系是这样的

class SalesArea extends Model
{
    public function regions() {
        return $this->belongsToMany(Region::class)->withPivot(['id'])->withTimestamps();
    }
}

class Region extends Model
{
    public function sales_area() {
        return $this->belongsToMany(SalesArea::class)->withPivot(['id'])->withTimestamps(
    }
}

然后你可以像这样做。
$salesArea = SalesArea::create($request->all());

$regions = Region::whereIn('id', [1, 2, 3])->get();

$salesArea->regions()->sync($regions->pluck('id')->toArray());

1
现实世界应用程序开发的本质是,区域已经存在,基本上不能改变。销售区域是一个新的概念,他们想要通过它将所有区域分组。因此,我们不能在创建区域时创建新的区域,而必须将现有的区域与新的销售区域分组。 - Oranges13
1
通过您的编辑,这将需要一个额外的表,不是吗?区域只能属于一个销售区域,因此hasMany/belongsTo关系更准确地反映了数据访问的需求。 - Oranges13
@Oranges13 刚刚更新了英文内容。我想知道您使用的关系是否确定。如果您知道自己在做什么,那么您可以忽略我关于更改关系的建议。 :) - prateekkathal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接