عنوان:

‫طراحی جدول فایل‌های پیوستی پایگاه داده


نویسنده: عثمان رحیمی
تاریخ: ۱۳۹۴/۱۰/۰۳ ۲۰:۵
آدرس: www.dntips.ir
سناریو‌ی زیر را در نظر بگیرید:
می‌خواهید پروژه‌ای را انجام دهید که شامل جداول زیر است:
مقالات، اخبار، گالری تصاویر، گالری ویدیو، اسلایدشو، تبلیغات و ... و تمامی این جداول حداقل شامل یک فایل پیوست (عکس، فیلم، ...) می‌باشند. به طور مثال جدول مقالات دارای یک عکس نیز می‌باشد. قصد داریم تمام فایل‌ها را بر روی هاست ذخیره کرده و فقط آدرس و نام فایل را در دیتابیس ذخیره نمایم.

روش اول : استفاده از یک فیلد در هر جدول برای نگه دارای اسم فایل

مثال:
    public class Article
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string Body { get; set; }
        public string RegisterDate { get; set; }
        public string FileName { get; set; }
    }
معایب:
این روش فقط در صورتی پاسخگو می‌باشد که هر رکورد فقط شامل یک فایل باشد. به طور مثال ممکن است برای یک مقاله، چندین عکس و فایل را ضمیمه‌ی آن کنیم. در این حالت این روش پاسخ گو نمی‌باشد؛ ولی می‌توانیم به صورت زیر نیز عمل کنیم:
ایجاد جدولی برای نگهداری فایل‌های هر رکورد از مقاله :


public class ArticleFiles
{
        public int Id { get; set; }
        public string FielName { get; set; }
        public string FileExtension { get; set; } 
        public Article Article { get; set; }
        public int FileSize { get; set; }
}
 
روش دوم : ایجاد جدولی پایه برای نگهدارای تمام فایل‌های آپلود شده

می‌توانیم جدولی را به نام Attachment ایجاد کرده و هر فایلی را که آپلود می‌کنیم، مشخصات آن را در این جدول ذخیره کنیم و هر جدول هم که نیازی به فایل داشت، رابطه‌ای با این جدول برقرار کند. در این حالت خواهیم داشت:


public class Attachment
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string FileName { get; set; }
        public string Extension { get; set; }
        public DateTime RegisterDate { get; set; }
        public int Size { get; set; }
        public ICollection<Article> ArticleFiles { get; set; }
        public ICollection<News> NewsFiles { get; set; }
        public int Viewed { get; set; }
    }
در این حالت باید بین تمام جداولی که نیاز به فایل دارند، رابطه ای با جدول Attachment داشته باشد. به طور مثال بین جدول مقالات و جدول Attachment یک رابطه‌ی یک به چند برای لیست فایل‌ها وجود خواهد داشت.


روش سوم : جدولی برای نگه داری اسم فایل‌ها، بدون رابطه

جدول Attachment در این روش، همانند روش دوم می‌باشد؛ با دو تفاوت:
1- با هیچ جدولی رابطه‌ای ندارد.
2- دو فیلد به عنوان نام جدول و Id رکورد به آن اضافه شده است.
تفاوت نسبت به روش دوم:
در روش دوم، ثبت یک رکورد، وابسته‌ی به ثبت رکورد در جدول Attachment بود و ابتدا می‌بایستی فایل در Attachment ذخیره می‌شد و بعد از بدست آوردن Id آن، رکورد مورد نظر (مقاله) را درج می‌کردیم. ولی در این روش ابتدا مقاله درج شده و بعد از آن فایل را با اسم جدول و ID رکورد مورد نظر ذخیره می‌کنیم:
public class Attachment
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string FileName { get; set; }
        public string Extension { get; set; }
        public DateTime RegisterDate { get; set; }
        public int Size { get; set; }
        public string TableName { get; set; }
        public int RowId { get; set; }
        public int Viewed { get; set; }        
    }

حالت پنجم :

ایجاد یک کلاس پایه و ارث بری سایر کلاس‌ها از کلاس پایه و ایجاد رابطه‌ای بین کلاس پایه و کلاس‌های مشتق شده.

نظراتی پیرامون حالت‌های مختلف:

1- داشتن یک جدول الحاقات برای هر جدول
  • اضافه کردن یک فیلد: بعضی‌ها این روش را ترجیح می‌دهند. به این دلیل که هر جدول، یک جدول attachment مختص به خود دارد؛ با توجه به فیلدهایی که لازم است. به طور مثال ممکن است بعد از گذشت مدتی، نیاز باشد تا دو فیلد برای فایل‌های هر مقاله اضافه شوند که در این حالت فقط به جدول attachment مقاله اضافه خواهند شد.

2- داشتن یک جدول پایه که کل فایل‌ها در آن ذخیره شوند (روش‌های دوم و سوم)

  • متمرکز شدن کل فایل‌ها در یک جدول: بیشتر پروژه‌ها و یا برنامه نویسان (طبق تجربه‌ی بنده) یک جدول پایه را برای این منظور دوست دارند. به دلیل اینکه تمام اطلاعات یکجا باشد.
  • عدم آپلود چندین باره‌ی یک فایل: در این حالت می‌توان از یک فایل چندین بار در چند جای مختلف استفاده نمود و در فضای هاست صرفه جویی می‌شود. این روش مدیریت سختی دارد و نیازمند کوئری‌های بیشتری می‌باشد.
  • وجود فیلد‌های زیاد null در جدول: در این حالت ممکن است ردیف‌هایی با ستون‌های مقدار null در جدول زیاد شوند. فرض کنید دو فیلد در جدول attachment وجود دارند که فقط توسط جدول مقالات مورد استفاده قرار می‌گیرند و در بقیه‌ی جداول بدون استفاده می‌باشند.


از کدام روش استفاده کنیم؟

نمی توان پیشنهاد کرد که الزاما از کدامیک از روش‌های بالا باید استفاده کنیم؛ چون نیازمندهای‌های هر پروژه با هم متفات است و نمی‌توان نسخه‌ای خاص را برای همه تجویز کرد.

نظرات

  • سالار ربال در ۱۳۹۴/۱۰/۰۷ ۱۳:۳۸
    با تشکر.
    به غیر از روش دوم و  حالت آخر در تمام مواردی که فرمودید ، نیاز است ابتدا به عنوان مثال مقاله درج شود و سپس بتوان مشخصات فایل را در جدول مورد نظر ثبت کرد ؛ یک حالت دیگر هم در صورتی که نیاز به Privacy نباشد ، میتوان در نظر گرفت که احتمال میدم در سایت جاری هم به این شکل استفاده میشود ، آن هم داشتن یک جدول فارغ از جداول دیگر  و تنها ارتباطی با جدول کاربران داشته باشد که مدلی به شکل زیر دارد : 
     public class Attachment
        {
    
            #region Properties
            /// <summary>
            /// sets or gets identifier for attachment
            /// </summary>
            public virtual Guid Id { get; set; }
            /// <summary>
            /// sets or gets name for attachment
            /// </summary>
            public virtual string FileName { get; set; }
            /// <summary>
            /// sets or gets type of attachment
            /// </summary>
            public virtual string ContentType { get; set; }
            /// <summary>
            /// sets or gets size of attachment
            /// </summary>
            public virtual long Size { get; set; }
            /// <summary>
            /// sets or gets Extention of attachment
            /// </summary>
            public virtual string Extensions { get; set; }
            /// <summary>
            /// sets or gets Creation Date
            /// </summary>
            public virtual DateTime CreatedOn { get; set; }
            /// <summary>
            /// gets or sets counts of download this file
            /// </summary>
            public virtual long DownloadsCount { get; set; }
    
            public virtual DateTime ModifiedOn { get; set; }
            #endregion
    
            #region NavigationProperties
            /// <summary>
            /// sets or gets identifier of attachment's owner
            /// </summary>
            public virtual long OwnerId { get; set; }
            /// <summary>
            /// sets or gets identifier of attachment's owner
            /// </summary>
            public virtual User Owner { get; set; }
            #endregion
        }
    در این حالت یکپارچه کردن ارسال فایل با ویرایشگر متن هم امکان پذیر خواهد بود و همچنین بازهم نیاز نیست فایلها چند باره ارسال شوند و به تفکیک هم میشود فایل‌های کاربران را در اختیارشان گذاشت.
    • مهدی ملائیان در ۱۳۹۷/۰۲/۲۳ ۱۵:۳۲
      با تشکر ، لطفا این بخش از پاسختون رو بیشتر توضیح بدهید:
      در این حالت یکپارچه کردن ارسال فایل با ویرایشگر متن هم امکان پذیر خواهد بود و همچنین بازهم نیاز نیست فایلها چند باره ارسال شوند 
      • عثمان رحیمی در ۱۳۹۷/۰۲/۲۴ ۰:۸
        در اکثر موراد مطرح شده فوق ، فایل‌های آپلود شده وابسته بوند به یک رکورد که ابتدا می‌بایست رکورد مورد نظر درج تا بتوان فایل را با آن کلید آپلود و ذخیره نمود .
        ولی در توضیح آقای ربال ، فرض کنید همین ادیتور سایت فعلی ، شما قصد نوشتن یک مقاله را دارید و لابه لای متون نیاز به قراردادن عکس هم دارید ، در این حالت سایت فعلی عکس مورد نظر ذخیره نموده و فقط آدرس آن برگشت داده میشود و داخل تگ src قرار داده می‌شود تا فایل نمایش داده شود . در این حالت فقط مشخص می‌شود که کاربر x فایل y  را آپلود کرده است .