Php 我的错在哪里?无法删除或更新父行:外键约束失败

Php 我的错在哪里?无法删除或更新父行:外键约束失败,php,sql,laravel,Php,Sql,Laravel,我试图从我的数据库中删除品牌和供应商,它们彼此相关,品牌与产品相关,我在执行最终删除之前删除这些关系(至少我认为是这样),我收到了这个错误,我不确定我遗漏了什么。最初在品牌模型中与产品没有关系,关系在产品模型中。我在没有运气的情况下将这种关系添加到品牌模型中,结果仍然是一样的 表结构 Schema::create('vendors', function (Blueprint $table) { $table->increments('id');

我试图从我的数据库中删除品牌和供应商,它们彼此相关,品牌与产品相关,我在执行最终删除之前删除这些关系(至少我认为是这样),我收到了这个错误,我不确定我遗漏了什么。最初在品牌模型中与产品没有关系,关系在产品模型中。我在没有运气的情况下将这种关系添加到品牌模型中,结果仍然是一样的

表结构

Schema::create('vendors', function (Blueprint $table)
        {
            $table->increments('id');
            $table->string('name');
            $table->string('image')->nullable();
            $table->timestamps();
        });

Schema::create('brands', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name')->nullable();
            $table->integer('vendor_id')->unsigned();;
            $table->foreign('vendor_id')->references('id')->on('vendors');
            $table->timestamps();
        });

Schema::create('products', function (Blueprint $table) {
            $table->increments('id');
            $table->string('code');
            $table->string('sku')->nullable();
            $table->text('description_spanish');
            $table->text('description_english');
            $table->string('image')->nullable();
            $table->string('discount');
            $table->string('cif')->nullable();
            $table->string('color')->nullable();
            $table->string('color_ab')->nullable();
            $table->integer('brand_id')->unsigned();
            $table->timestamps();

            $table->foreign('brand_id')->references('id')->on('brands');
        });
模型和关系

class Vendor extends Model
{
    protected $hidden = ['created_at','updated_at'];

    public function  brands(){
        return $this->hasMany(Brand::class);
    }
}

class Brand extends Model
{
    public function vendor() {
        return $this->belongsTo(Vendor::class);
    }

    public function products() {
        return $this->hasMany(Product::class);
    }

}

class Product extends Products
{
    public function brand()
        {
            return $this->belongsTo(Brand::class);
        }
}
销毁控制器中的函数

供应商销毁功能

public function destroy($id)
    {
        DB::beginTransaction();
        $vendor = Vendor::findOrFail($id);
        $vendor->brands()->delete();
        $vendor->delete();
        DB::commit();

    }
public function destroy($id)
    {
        DB::beginTransaction();
        $brand= Brand::findOrFail($id);
        $brand->vendor()->delete();
        $brand->products()->delete();
        $brand->delete();
        DB::commit();
    }
品牌破坏功能

public function destroy($id)
    {
        DB::beginTransaction();
        $vendor = Vendor::findOrFail($id);
        $vendor->brands()->delete();
        $vendor->delete();
        DB::commit();

    }
public function destroy($id)
    {
        DB::beginTransaction();
        $brand= Brand::findOrFail($id);
        $brand->vendor()->delete();
        $brand->products()->delete();
        $brand->delete();
        DB::commit();
    }
积破坏函数

public function destroy($id)
    {
        $product = Product::findOrFail($id);
        DB::beginTransaction();
        $product->sizes()->detach();
        $product->tags()->detach();
        $product->fields()->detach();
        $product->countries()->detach();
        $this->removeProductImage($product);
        $product->exportationFactors()->delete();
        $product->delete();
        DB::commit();
    }
当我尝试删除供应商时,我收到此错误

SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update
 a parent row: a foreign key constraint fails (`sondel`.`products`, CONSTRAINT 
`products_brand_id_foreign` FOREIGN KEY (`brand_id`) REFERENCES `brands` 
(`id`)) (SQL: delete from `brands` where `brands`.`vendor_id` = 1 and 
`brands`.`vendor_id` is not null)
当我试图删除一个品牌时,我基本上有相同的错误

SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update 
a parent row: a foreign key constraint fails (`sondel`.`brands`, CONSTRAINT 
`brands_vendor_id_foreign` FOREIGN KEY (`vendor_id`) REFERENCES `vendors` 
(`id`)) (SQL: delete from `vendors` where `vendors`.`id` = 1)
在每个
$table->foreign(“”)
上添加
onDelete('cascade')

例如:

$table->foreign('vendor_id')->references('id')->on('vendors')->onDelete('cascade');

然后,无需先删除所有子项,只需删除父项。

您遇到的问题在产品表中,有两种方法可以解决此问题:

解决方案1:

正如Yovi的回答所述,您可以简单地将
onDelete('cascade')
添加到您的brands&products表的外键中

品牌表:

$table->foreign('vendor_id')->references('id')->on('vendors')->onDelete('cascade');
产品表:

$table->foreign('brand_id')->references('id')->on('brands')->onDelete('cascade');
那么您的控制器销毁方法应该如下所示: 供应商销毁功能:

public function destroy($id)
{
    $vendor = Vendor::findOrFail($id);
    $vendor->delete();

}
public function destroy($id)
{
    DB::beginTransaction();
    $vendor = Vendor::findOrFail($id);

    foreach($vendor->brands() as $brand){
        $brand->products()->delete();
    }

    $vendor->brands()->delete();
    $vendor->delete();
    DB::commit();
}
public function destroy($id)
{
    DB::beginTransaction();
    $brand= Brand::findOrFail($id);
    $brand->products()->delete();
    $brand->delete();
    DB::commit();
}
品牌销毁方法:

public function destroy($id)
{
    $brand= Brand::findOrFail($id);
    $brand->delete();
}
解决方案2:

如果要手动删除行,只需在销毁方法上设置了错误的顺序即可。您必须首先从产品->品牌->供应商处删除最小的子项。您的方法应该如下所示:

供应商销毁功能:

public function destroy($id)
{
    $vendor = Vendor::findOrFail($id);
    $vendor->delete();

}
public function destroy($id)
{
    DB::beginTransaction();
    $vendor = Vendor::findOrFail($id);

    foreach($vendor->brands() as $brand){
        $brand->products()->delete();
    }

    $vendor->brands()->delete();
    $vendor->delete();
    DB::commit();
}
public function destroy($id)
{
    DB::beginTransaction();
    $brand= Brand::findOrFail($id);
    $brand->products()->delete();
    $brand->delete();
    DB::commit();
}
品牌破坏功能:

public function destroy($id)
{
    $vendor = Vendor::findOrFail($id);
    $vendor->delete();

}
public function destroy($id)
{
    DB::beginTransaction();
    $vendor = Vendor::findOrFail($id);

    foreach($vendor->brands() as $brand){
        $brand->products()->delete();
    }

    $vendor->brands()->delete();
    $vendor->delete();
    DB::commit();
}
public function destroy($id)
{
    DB::beginTransaction();
    $brand= Brand::findOrFail($id);
    $brand->products()->delete();
    $brand->delete();
    DB::commit();
}

总的来说,我发现解决方案1要干净得多。

如果您想在删除记录时始终删除所有子关系,可以在删除方法上的模型启动功能中执行此操作。大概是这样的:

供应商模型

类供应商扩展模型
{
公共静态函数boot(){
父::boot();
//删除供应商时,还应删除所有相关品牌
静态::删除(函数($vendor){
$vendor->brands->每个功能($brand){
$brand->delete();
});
});
}
受保护的$hidden=['created_at','updated_at'];
公共功能品牌(){
返回$this->hasMany(Brand::class);
}
}
品牌模式

class品牌扩展模型
{
公共静态函数boot(){
父::boot();
//删除品牌时,还应删除所有相关产品
静态::删除(函数($brand){
$brand->products->每个功能($product){
$product->delete();
});
});
}
公共功能供应商(){
返回$this->belongsTo(供应商::类);
}
公共功能产品(){
返回$this->hasMany(Product::class);
}
}
产品模型

类产品扩展产品
{
公共静态函数boot(){
父::boot();
//删除产品时,还需要删除/分离所有需要的内容
静态::删除(函数($product){
/*
$product->sizes()->detach();
$product->tags()->detach();
$product->fields()->detach();
$product->countries()->detach();
$product->EXPORTANGFACTORS->每个功能($EXPORTANGFACTORE){
$exportationFactor->delete();
});
*/
});
}
公共功能品牌()
{
返回$this->belongsTo(Brand::class);
}
}
然后在控制器中,只需删除每个控制器对应的记录

供应商销毁功能

public function destroy($id)
    {
        DB::beginTransaction();
        $vendor = Vendor::findOrFail($id);
        $vendor->brands()->delete();
        $vendor->delete();
        DB::commit();

    }
public function destroy($id)
    {
        DB::beginTransaction();
        $brand= Brand::findOrFail($id);
        $brand->vendor()->delete();
        $brand->products()->delete();
        $brand->delete();
        DB::commit();
    }
公共功能销毁($id)
{
DB::beginTransaction();
Vendor::findOrFail($id)->delete();
DB::commit();
}
品牌破坏功能

public function destroy($id)
    {
        DB::beginTransaction();
        $vendor = Vendor::findOrFail($id);
        $vendor->brands()->delete();
        $vendor->delete();
        DB::commit();

    }
public function destroy($id)
    {
        DB::beginTransaction();
        $brand= Brand::findOrFail($id);
        $brand->vendor()->delete();
        $brand->products()->delete();
        $brand->delete();
        DB::commit();
    }
公共功能销毁($id)
{
DB::beginTransaction();
Brand::findOrFail($id)->delete();
DB::commit();
}
积破坏函数

public function destroy($id)
    {
        $product = Product::findOrFail($id);
        DB::beginTransaction();
        $product->sizes()->detach();
        $product->tags()->detach();
        $product->fields()->detach();
        $product->countries()->detach();
        $this->removeProductImage($product);
        $product->exportationFactors()->delete();
        $product->delete();
        DB::commit();
    }
公共功能销毁($id)
{
$product=产品::findOrFail($id);
DB::beginTransaction();
$this->removeProductImage($product);
$product->delete();
DB::commit();
}

$vendor->vendors()
选择所有供应商。delete尝试删除它们。无法删除它们,因为您添加了约束。您要删除的是
供应商
,而不是
供应商
@Ibu I为了清晰起见进行了编辑,因此可能会有所不同,
$vendor->vendors
是否在品牌销毁功能中?是否可能复制到与品牌、供应商、,我在删除数据库中的其他内容时没有遇到任何问题,只有这些品牌和供应商当我尝试此操作时,我会得到相同的错误,但它引用的是与产品表相关的另一个表,
->onDelete('cascade')工作,但并不完全符合我的要求。我想如果我删除了一个供应商,那么所有相关的品牌和产品也会被删除,但是如果我删除了一个品牌,相关的产品会被删除,而不是供应商。通过级联,所有东西都删除了对我来说只有一半有效的东西。我不能让一个品牌删除一个供应商或者我的第一个解决方案是,我不希望该品牌能够删除一个供应商,当我使用onDelete cascade时,所有东西都可以删除所有东西,因为在供应商删除品牌时,与之相关的产品是好的,这就是我想要的,但品牌应该只能删除与供应商无关的产品。在第二个解决方案中,我遇到了一些问题,因为我现在调用了与产品的关系,所以它也调用了内部的所有产品关系