【问题标题】:Why can't I delete this from my tables that have relationships?为什么我不能从有关系的表中删除它?
【发布时间】:2020-01-13 16:01:35
【问题描述】:

为什么我不能从我的数据库中删除这些项目,它们每个只有一个关系,我分别分离和删除每个。我有 3 个表供应商、品牌和产品。该错误提到了 Products 表,但 Vendor 表与 Products 表没有关系,该关系与 Brand 表是一对一的关系。

表结构

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 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();
        $vendor = Brand::findOrFail($id);
        $vendor->vendors()->delete();
        $vendor->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` = 2 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` = 2)

我不确定自己做错了什么。

【问题讨论】:

  • 第一条错误消息提到了一个products 表,您没有显示。
  • @Barmar 我已将产品表信息添加到问题中
  • 为什么vendorbrand 中的FK?这意味着一个品牌只能由一个供应商销售。这似乎应该是一个多对多的关系,所以你应该有一个将它们关联起来的联结表。
  • 按照您的方式,在删除供应商之前,您必须删除它销售的所有品牌。在您删除某个品牌之前,您必须先删除该品牌的所有产品。
  • 假设您使用的是MYSQL,如果与其他表的另一条记录有关系,则不能删除记录,除非您在数据库中定义表时使用“on delete cascade”,您可以检查Laravel 创建这些表时运行的 SQL 是什么。

标签: php database laravel laravel-query-builder


【解决方案1】:

供应商删除错误是因为您正在删除供应商的所有与产品再次相关的品牌,因此,如果不删除其相关产品,您将无法删除它们。 因此,您必须首先删除产品。在品牌模型上创建产品关系

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

然后在 Vendor's destroy 时让其所有品牌循环并删除所有产品。

DB::beginTransaction();
$vendor = Vendor::findOrFail($id);
$vendor->brands->each(function ($brand) {
    $brand->products->each(function ($product) {
         $product->sizes()->detach();
         $product->tags()->detach();
         $product->fields()->detach();
         $product->countries()->detach();
         $this->removeProductImage($product);
         $product->exportationFactors()->delete();
         $product->delete();
    });
});
$vendor->brands()->delete();
$vendor->delete();
DB::commit();

Same On Brand 的 delete 获取其所有产品,并先删除其产品。

DB::beginTransaction();
$brand = Brand::findOrFail($id);
$brand->products->each(function ($product) {
     $product->sizes()->detach();
     $product->tags()->detach();
     $product->fields()->detach();
     $product->countries()->detach();
     $this->removeProductImage($product);
     $product->exportationFactors()->delete();
     $product->delete();
});
$brand->delete();
DB::commit();

我建议你在所有三个模型上都使用 Eloquent 的删除事件,这样你就不需要关心嵌套模型的外键,你将摆脱代码重复。见:https://laravel.com/docs/6.0/eloquent#events

【讨论】:

    猜你喜欢
    • 2020-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多