محمد امین
محمد امین
خواندن ۳ دقیقه·۵ سال پیش

استفاده از فیلدهای Unique در دیتابیس با Soft Delete

اگر تا الان می‌خواستید که از ویژگی soft delete به همراه unique fields استفاده کنید، احتمالا متوجه شدید که خیلی با هم هماهنگ نیستن. ممکنه یک رکورد رو پاک کنید و انتظار داشته باشید که بتونین رکورد جدیدی با همون دیتا ثبت کنید، اما به مشکل خورده. بیاین با هم بررسی کنیم چقدر این مسئله مهمه و چجوری میتونیم حلش کنیم.

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

برای من اعتبارسنجی در سطح دیتابیس مثل اعتبار سنجی فرانت اند میمونه. درسته که از لحاظ تجربه کاربری چک کردن فرمت ایمیل کاربر در فرم های فرانت اند حس خوبی میده اما اگر کاربری چک های فرانت رو حذف کنه به راحت میتونه تو روال کد خطا ایجاد کنه.

از طرفی تا ۹۹ درصد سیستم هایی که طراحی میشه نیاز به ایجاد فیلد unique در سطح دیتابیس داره.مثلا باید ایمیل، نام کاربری یا تلفن کاربر unique باشه. حالا اگر کاربری بخواد اکانتشو پاک کنه و ما بهش اجازه soft delete دادیم. آیا دیگ اون فرد اجازه نداره با اون شماره، ایمیل یا نام کاربری تو سیستم ما اکانت داشته باشه؟ یا اینکه به صورت سیستمی تو کد بکند چک میکنیم که اکانت با این اطلاعات موجوده یا نه؟



خوب اوکی حالا مسئله رو متوجه شدیم و فهمیدیم که فیلد unique مهمه و باید استفاده بشه، اما استفاده همزمان اون با soft delete غیر عملیه!!!

فرض کنید یک سیستم فروشگاهی طراحی کردید و به خاطر فروش های گذشته نمی‌خواید تا محصولات ناموجود رو از دیتابیس پاک کنید.پس تصمیم میگیرید با اضافه کردن یک ستون (مثلا deleted_at ) چک کنید که اون پاک شده یا نه. حالا اگر محصولی soft delete بشه ،باید کاربر بتونه محصولی رو دقیقا با همون مشخصات وارد دیتابیس کنه. اما از اون اونجایی که مثلا نام کالا به عنوان یک فیلد unique تو دیتابیس بوده عملا نمیتونه دیتا رو وارد کنه.

راه حل چیه؟ ما مقدار فیلد deleted_at رو به صورت پیش فرض null میزاریم.راه حلی که برای این مشکل هست اینه که به جای unique کردن یک فیلد ، ترکیبی از فیلدها رو unique کنیم.

ALTER TABLE products ADD UNIQUE KEY name_deleted_at_unique_key (name, deleted_at);

اینجوری ترکیب دو تا فیلد name و deleted_at رو unique میکنیم و دیگ اگر رکوردی soft delete شده بود برای ما مشکلی پیش نمیاره.

باز هم یک مشکل کوچیک؟ من تو دیتابیس postgres تست کردم و تونستم ترکیب یک فیلد با مقدار null و یک فیلد دیگ رو unique کنم. اما دیدم تو mysql نمیشه فیلدی با مقدار null رو به عنوان unique اضافه کرد. اینجا هم یه تریک کوچیکی میشه زد.

فیلد deleted_at از نوع timestamp هستش و مقدار پیش فرضش هم null هست.میتونیم به جای این کار از مقدار 0 به عنوان پیش فرض استفاده کنیم.

deleted_at int(11) NOT NULL DEFAULT 0

البته اینجا ممکنه یکم مبهم باشه چون مقدار صفر در فیلد از نوع timestamp برابر میشه با اول ژانویه 1970 . ولی خوب از اونجایی که اپ شما اون موقع وجود نداشته و به اون تاریخ هم خیلی کار نداره مقدار صفر با درصد زیادی میتونه یک مقدار مطمئن برای این فیلد باشه تا بفهمیم که مقدار deleted_at خالیه.

من این موضوع رو برای یک پروژه با دیتابیس postgres انجام دادم و جواب داد ، اما روی سایر دیتابیس ها کار نکردم و از جوابش مطمئن نیستم.اگر کسی تجربه این کارو داشت به منم یاد بده.


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