محمد رضا
3 سال پیش توسط محمد رضا مطرح شد
5 پاسخ

ارتباط چند به چند یک جدول با خودش many-to-many from the same table

سلام و درود خدمت همه ی دوستان و عزیزان راکتی
اقا من یک پروژه ای دارم که نیاز به ارتباط چند به چند یک جدول با خودشه.
برای درک نیاز این موضوع مثال برنامه اینستا رو داشته باشید که هر کار بر چندین دنبال کننده و چندین دنبال شونده داره
موضوع رو در لینکی که زیر قرار میدم میتونید بهتر ببینیدو خودش هم راهنمایی داره که من درست متوجهش نشدم.
many-to-many from the same table

حالا سناریو خودم رو توضیح میدم که چی هست صحنه که دوستان بهتر بتونن بنده رو راهنمایی کنن
من دارم برای یه رستوران غذای آماده پروژه ای مینویسم
موضوع برای غذا های این پروژه هست در زمانی که میخوام سفارشی رو ثبت کنم و موجودی اون غذا کم کنم.

قضیه اینطوریه که در غذای آمده ای مثلا شما صد پرس چلو داری ، پنجاه تا جوجه ، پنجاه تا کوبیده (فرض مسئله)
خب برای فروش سفارش ها به صورت چلو جوجه کباب و چلو کباب کوبیده هست که هم چلو توشه هم کوبیده یا جوجه
چلو یه موجودی داره و جوجه هم همینطور
جوجه به تنهایی و چلو هم به تنهایی قابل فروش هست
یعنی نمیشه بگیم فقط غذای چلو جوجه کباب داریم و چلوی تنها رو نمیدیو یا جوجه ی تنها رو نمیتونیم بدیم
پس قرار دادن موجودی برای چلو جوجه کباب بی معنی میشه چون با فروش اون باید یکی از موجودی چلو ها و یکی از موجودی جوجه ها کم بشه

حالا اینجا یک غذا (چلو جوجه کباب ) دو تا پدر (چلو و جوجه ) رو داره و چلو هم دو تا فرزند (چلو جوجه کباب و چلو کباب کوبیده ) رو داره

در کل قراره محصولی که پدری داره موجودی ای نداشته باشه و با فروش اون از موجودی تمام پدر هاش یکی کم بشه
مثلا با فروش چلو جوجه کباب از موجودی دو پدرش که چلو و جوجه هست یکی کم بشه

تنها روشی ک ب فکرم میرسه رابطه چند به چند جدول محصولاتم با خودشه
جدول محصولات (که غذا هم شاملشه) و دسته بندیمم به شکل زیره:

Schema::create('categories', function (Blueprint $table) {
    $table->id();
    $table->string('name');

});
Schema::create('products', function (Blueprint $table) {
    $table->id();
    $table->string('name')->unique();
    $table->integer('price')->default(0);
    $table->integer('stock')->default(0);

});
Schema::create('category_product',function (Blueprint  $table){
    $table->unsignedBigInteger('category_id');
    $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
    $table->unsignedBigInteger('product_id');
    $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
    $table->primary(['category_id','product_id']);
});

بخش ثبت محصولات (غذا ها و ... )در حالت فعلی رو میتونید ببینید که هنوز این بحثی که گفتم بهش اضاف نشده و برای حساب کتاب موجودی هاش لازمه واقعا
صفحه ی محصولات


ثبت پرسش جدید
محمد رضا
تخصص : Full Stack Developer
@salar.mohammad2013 3 سال پیش مطرح شد
2

اقا بر اساس لینکی که اول فرستادم با بررسی های خیلی بیشتر موفق به انجامش شدم
فقط کافیه یه جدول دیگه با هر نامی که دوس داری ایجاد کنی
داخل جدول جدید دو تا ستون باز هم با هر نامی که دوس دارید ایجاد میکنید و مرتبط میکنید جفتشو به عنوان کلید خارجی به کلید اصلی جدولی که میخوایید ارتباط چند به چند با خودش داشته باشه
توی مثال من parent_id و child_id کلید خارجی برای id از جدول prodcuts هستند

Schema::create('products', function (Blueprint $table) {
    $table->id();
    $table->string('name')->unique();
    $table->integer('price')->default(0);
    $table->integer('stock')->default(0);

});

Schema::create('foods',function (Blueprint  $table){
    $table->unsignedBigInteger('parent_id');
    $table->foreign('parent_id')->references('id')->on('products')->onDelete('cascade');
    $table->unsignedBigInteger('child_id');
    $table->foreign('child_id')->references('id')->on('products')->onDelete('cascade');
    $table->primary(['parent_id','child_id']);
});

در مرحله ی اخر هم این ارتباط رو در مدل خودتون قرار میدین
نیاز نیست برای این جدول جدید مدل بسازید
من فقط در مدل product این قطعه کد پایین رو قرار دادم

    public function parents() {
        return $this->belongsToMany(Product::class, 'foods', 'child_id', 'parent_id');
    }

    public function childs() {
        return $this->belongsToMany(Product::class, 'foods', 'parent_id', 'child_id');
    }

در رابطه با طریقه ی کم کردن موجودی محصولات پدر در یک حلقه برای هر محصول قطعه کد زیر رو زدم
که به این صورت هست که اگر این محصول پدری داره بره از هر پدرش موجودی رو کم کنه اگر هم نداره فقط از خودش کم کنه

            if (Product::find($product['product_id'])->parents->count()){
                foreach (Product::find($product['product_id'])->parents as $parent){
                    DB::table('products')->where('id',$parent['id'])->decrement('stock', $product['count']);
                }

            }else{
                DB::table('products')->where('id',$product['product_id'])->decrement('stock', $product['count']);
            }

@msdabbagh
@mohaligateway


محمدسجاد دباغ
تخصص : برنامه نویس لاراول
@mdabbagh 3 سال پیش مطرح شد
0

سلام!
فکر میکنم اگر جدول غذاهای پایه ( برنج ، مرغ ، کباب و ... ) جدا باشه و یک جدول هم برای غذاهای ترکیبی ( برنج + مرغ ) ایجاد بشه بهتر باشه.
و جدول غذای ترکیبی رابطه یک به چند با جدول پایه داشته باشه و موقع سفارش غذای ترکیبی ، لیست غذای های پایه فراخوانی و کم بشه.
جدول ترکیبی میتونه هم یک عنوان بگیره تا به جای برنج و مرغ ، کاربر بنویسه چلومرغ


محمد رضا
تخصص : Full Stack Developer
@salar.mohammad2013 3 سال پیش مطرح شد
0

مرسی ایده ی جالبی بود
ولی در مرحله ی اول این که چون قراره این محصولات نمایش داده بشن (تصویری که در انتها قرار دادم) انتخاب محصولات مختلف از جداول مختلف که یک ویژگی مشترک دارن همشون و بعد فهمیدن این که ایدی این محصول برای کدوم جدول و محصوله برای افزودن، حذف ، ویرایش به شدت به نظرم حجم کد رو بالا میبره و دستورات شرطی رو زیاد میکنه

برای قضیه که گفتید به جای برنج و مرغ کاربر مینویسه چلو مرغ، بله قرار نیست کاربر دوتا رو برای یک سفارش بنویسه

در تعریف محصول، کاربر میزان پرس برنج و سیخ جوجه رو که باید جدا مشخص کنه و جدا هم میتونه بفروشه پس به صورت جدا تعریف و میتونن انتخاب بشن
اما محصولی که دارای پدر هست موقع تعریف پدر هاش مشخص میشن مثلا همونطور که گفتم غذایی با اسم چلو مرغ دارای دو پدر چلو و مرغ هست

من توی دسته بندی ها هم رابطه ای که گذاشتم یک محصول میتونه چند دسته بندی داشته باشه و ب راحتی انتخاب و نمایش داده میشه
دسته بندی ها

ثبت فاکتور


moha li
تخصص : توسعه دهنده لاراول و Vue
@mohaligateway 3 سال پیش مطرح شد
0

سلام
برای اینکه دوستان بتونن بهتر به شما دوست عزیز کمک کنن اگه بتونید یک فلو چارت ارائه بدید راحت تر می شه🌹
@salar.mohammad2013


محمد رضا
تخصص : Full Stack Developer
@salar.mohammad2013 3 سال پیش مطرح شد
0

ب نظرم تا جایی که تونستم کامل توضیح دادم
چیزی که نیاز هست ارتباط چند به چند یک جدول با خودشه
مثل قضیه ای که لینکش رو در ابتدای بحث قرار دادم
اگر جایی ابهام هست سوال کنید توضیح بدم
@mohaligateway


محمد رضا
تخصص : Full Stack Developer
@salar.mohammad2013 3 سال پیش مطرح شد
2

اقا بر اساس لینکی که اول فرستادم با بررسی های خیلی بیشتر موفق به انجامش شدم
فقط کافیه یه جدول دیگه با هر نامی که دوس داری ایجاد کنی
داخل جدول جدید دو تا ستون باز هم با هر نامی که دوس دارید ایجاد میکنید و مرتبط میکنید جفتشو به عنوان کلید خارجی به کلید اصلی جدولی که میخوایید ارتباط چند به چند با خودش داشته باشه
توی مثال من parent_id و child_id کلید خارجی برای id از جدول prodcuts هستند

Schema::create('products', function (Blueprint $table) {
    $table->id();
    $table->string('name')->unique();
    $table->integer('price')->default(0);
    $table->integer('stock')->default(0);

});

Schema::create('foods',function (Blueprint  $table){
    $table->unsignedBigInteger('parent_id');
    $table->foreign('parent_id')->references('id')->on('products')->onDelete('cascade');
    $table->unsignedBigInteger('child_id');
    $table->foreign('child_id')->references('id')->on('products')->onDelete('cascade');
    $table->primary(['parent_id','child_id']);
});

در مرحله ی اخر هم این ارتباط رو در مدل خودتون قرار میدین
نیاز نیست برای این جدول جدید مدل بسازید
من فقط در مدل product این قطعه کد پایین رو قرار دادم

    public function parents() {
        return $this->belongsToMany(Product::class, 'foods', 'child_id', 'parent_id');
    }

    public function childs() {
        return $this->belongsToMany(Product::class, 'foods', 'parent_id', 'child_id');
    }

در رابطه با طریقه ی کم کردن موجودی محصولات پدر در یک حلقه برای هر محصول قطعه کد زیر رو زدم
که به این صورت هست که اگر این محصول پدری داره بره از هر پدرش موجودی رو کم کنه اگر هم نداره فقط از خودش کم کنه

            if (Product::find($product['product_id'])->parents->count()){
                foreach (Product::find($product['product_id'])->parents as $parent){
                    DB::table('products')->where('id',$parent['id'])->decrement('stock', $product['count']);
                }

            }else{
                DB::table('products')->where('id',$product['product_id'])->decrement('stock', $product['count']);
            }

@msdabbagh
@mohaligateway


برای ارسال پاسخ لازم است وارد شده یا ثبت‌نام کنید

ورود یا ثبت‌نام