آموزش پیشرفته Data Annotations در Entity Framework Core، یکی از راههای تعریف ویژگیها و تنظیمات مربوط به مدلها (کلاسهایی که نمایندهی جدولها در دیتابیس هستند)، استفاده از Data Annotationها یا همان حاشیهنویسیهای دادهای است. این Data Annotationها در واقع Attributeهایی هستند که مستقیماً بالای کلاسها یا پراپرتیها نوشته میشوند و به EF Core کمک میکنند تا بداند:این Data Annotationها در واقع Attributeهایی هستند که مستقیماً بالای کلاسها یا پراپرتیها نوشته میشوند و به EF Core کمک میکنند تا بداند:
این روش یک راه ساده، سریع و مستقیم برای تنظیم رفتار مدلهاست، بدون اینکه نیازی به استفاده از روش پیچیدهتر Fluent API داشته باشیم.
| Attribute | توضیح | مثال |
|---|---|---|
| [Key] | تعیین پراپرتی به عنوان کلید اصلی جدول | [Key] |
| [Required] | الزامی بودن فیلد (NULL نپذیرد) | [Required] |
| [StringLength] | تعیین حداقل و حداکثر طول مجاز برای رشته | [StringLength(50, MinimumLength = 2)] |
| [MaxLength] | تنها تعیین حداکثر طول رشته | [MaxLength(100)] |
| [MinLength] | تنها تعیین حداقل طول رشته | [MinLength(3)] |
| [Column] | تعیین نام یا نوع ستون در دیتابیس | [Column("Full_Name", TypeName = "varchar(100)")] |
| [Table] | تغییر نام جدول پیشفرض در دیتابیس | [Table("tbl_users")] |
| [DatabaseGenerated] | تعیین نوع تولید مقدار (Identity, Computed, None) | [DatabaseGenerated(DatabaseGeneratedOption.Identity)] |
| [ForeignKey] | تعیین کلید خارجی به صورت صریح | [ForeignKey("UserId")] |
| [InverseProperty] | برای تنظیم روابط دوطرفه در مدلهای پیچیده | [InverseProperty("Orders")] |
| [NotMapped] | از این پراپرتی ستونی در دیتابیس ساخته نشود | [NotMapped] |
| [Timestamp] | برای کنترل همزمانی (Concurrency) | [Timestamp] |
| [ConcurrencyCheck] | کنترل همزمانی روی یک پراپرتی خاص | [ConcurrencyCheck] |
| [Range] | محدود کردن مقدار عددی یا تاریخ بین یک بازه خاص | [Range(1, 100)] |
| [DataType] | تعیین نوع داده برای نمایش و اعتبارسنجی | [DataType(DataType.Date)] |
| [EmailAddress] | اعتبارسنجی فرمت ایمیل | [EmailAddress] |
| [Phone] | اعتبارسنجی شماره تلفن | [Phone] |
| [Url] | اعتبارسنجی URL (آدرس اینترنتی) | [Url] |
| [CreditCard] | اعتبارسنجی شماره کارت اعتباری | [CreditCard] |
| [RegularExpression] | اعتبارسنجی با الگوی regex خاص | [RegularExpression(@"^\d{10}$")] |
| [Compare] | مقایسه دو فیلد (مثلاً پسورد و تکرار پسورد) | [Compare("Password")] |
| Attribute | توضیح | مثال |
|---|---|---|
| [ScaffoldColumn(false)] | از نمایش این پراپرتی در صفحات Scaffold یا فرمهای خودکار جلوگیری میکند. | [ScaffoldColumn(false)] |
| [BindNever] | از Bind شدن این فیلد به فرم ورودی جلوگیری میکند (مثلاً فیلدهای سیستمی). | [BindNever] |
| [BindRequired] | الزام میکند که فیلد حتماً مقداردهی شود هنگام Bind شدن. | [BindRequired] |
| [Display(Name = “…”)] | نام نمایشی برای فیلد در فرمها و رابط کاربری تعیین میکند. | [Display(Name = "Full Name")] |
| [DisplayFormat] | فرمت نمایش داده برای فیلد (مثلاً تاریخ، پول، درصد). | [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)] |
| [Editable(false)] | فیلد را فقط خواندنی (read-only) میکند در فرمها. | [Editable(false)] |
| [UIHint(“TemplateName”)] | برای استفاده از یک قالب (Template) سفارشی در فرمها. | [UIHint("MultilineText")] |
| [HiddenInput(DisplayValue = false)] | نمایش فیلد به صورت input hidden در فرمها (ASP.NET MVC). | [HiddenInput(DisplayValue = false)] |
اگر بخواهیم یک مثال بزنیم، Data Annotation مثل علامتهایی است که مستقیم روی دیوار میچسبانی تا به بقیه بگویی هر چیزی کجا باید قرار بگیرد — سریع، ساده، و واضح!
| مورد | کد کامل Data Annotation |
|---|---|
| شماره موبایل ایران | |
| شماره تلفن ثابت ایران | |
| شماره کارت بانکی | |
| کد ملی ایران | |
| شماره شناسنامه | |
| کد پستی ایران | |
| شناسه ملی شرکت | |
| شماره حساب بانک ملت | |
| ایمیل با دامنه .ir | |
| فقط حروف فارسی | |
| حروف و اعداد فارسی | |
| شماره پلاک خودرو | |
[Table("tbl_user_profiles")] // تغییر نام جدول در دیتابیس
public class UserProfile
{
// کلید اصلی که توسط دیتابیس بهصورت افزایشی تولید میشود
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[HiddenInput(DisplayValue = false)] // در فرم HTML به صورت hidden
public int Id { get; set; }
// فیلد ضروری با حداقل و حداکثر طول مشخص
[Required]
[StringLength(100, MinimumLength = 3)]
[Display(Name = "Full Name")]
public string FullName { get; set; }
// اعتبارسنجی ایمیل
[Required]
[EmailAddress]
[Column(TypeName = "varchar(100)")]
public string Email { get; set; }
// اعتبارسنجی شماره تلفن با regex مخصوص شمارههای ایرانی
[Required]
[RegularExpression(@"^09\d{9}$", ErrorMessage = "شماره موبایل باید با ۰۹ شروع شود و ۱۱ رقم باشد")]
[StringLength(11, MinimumLength = 11)]
[Display(Name = "Mobile Number")]
public string PhoneNumber { get; set; }
// فیلد آدرس سایت – URL معتبر
[Url]
public string Website { get; set; }
// شماره کارت اعتباری (برای تمرین)
[CreditCard]
[Display(Name = "Credit Card Number")]
public string CreditCard { get; set; }
// سن بین ۱۸ تا ۹۹ سال
[Range(18, 99)]
public int Age { get; set; }
// تاریخ تولد با فرمت خاص نمایش
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime BirthDate { get; set; }
// فیلدی که فقط در کد مقدار میگیرد، نه از فرم (BindNever)
[BindNever]
public bool IsAdmin { get; set; }
// فیلدی که باید در فرم ارسال شود، وگرنه خطا میدهد
[BindRequired]
public string Username { get; set; }
// فیلد فقطخواندنی در فرم
[Editable(false)]
public string CreatedBy { get; set; }
// فیلد محاسباتی که در دیتابیس ذخیره نمیشود
[NotMapped]
public string FullNameUpper => FullName?.ToUpper();
// توضیحات بلند با قالب نمایشی چند خطی در فرم
[UIHint("MultilineText")]
public string Bio { get; set; }
// رمز عبور: مقدار اصلی
[Required]
[DataType(DataType.Password)]
[StringLength(100, MinimumLength = 6, ErrorMessage = "رمز عبور باید حداقل ۶ کاراکتر باشد.")]
public string Password { get; set; }
// تکرار رمز عبور: برای مقایسه با رمز اصلی
[Compare("Password", ErrorMessage = "رمز عبور و تکرار آن یکسان نیست.")]
[DataType(DataType.Password)]
[Display(Name = "Confirm Password")]
public string ConfirmPassword { get; set; }
// کنترل همزمانی برای مدیریت تغییرات همزمان رکورد
[Timestamp]
public byte[] RowVersion { get; set; }
// فیلدی که در Scaffold نمایش داده نشود (مثلاً برای سیستم)
[ScaffoldColumn(false)]
public DateTime CreatedAt { get; set; } = DateTime.Now;
}
نکته مهم: در پروژههای بزرگتر و پیچیدهتر Asp.Net Core، معمولاً از Fluent API برای تنظیم دقیقتر و منعطفتر استفاده میشود، ولی Data Annotation همچنان یک ابزار بسیار قدرتمند و کارآمد است برای تنظیمات ابتدایی و متداول.
از Data Annotationها برای اعتبارسنجی، نمایش بهتر فرمها و تنظیم رفتار فیلدها استفاده میشود؛ اما جایگاه استفاده آنها بسته به نوع کلاس (Model یا ViewModel) متفاوت است.
در Entity Modelها (مدلهای EF Core)، Data Annotationهایی مانند [Key], [ForeignKey], [DatabaseGenerated], [Timestamp] و [NotMapped] برای مدیریت ساختار دیتابیس به کار میروند.
در مقابل، ViewModelها برای نمایش و دریافت اطلاعات از کاربر طراحی شدهاند، بنابراین در آنها از Annotationهایی مثل [Required], [StringLength], [Display], [UIHint], [Compare] و [RegularExpression] برای اعتبارسنجی فرم و کنترل ظاهر استفاده میشود.
نتیجه: هر جا با دیتابیس سروکار داری، از Data Annotationهای EF استفاده کن؛ و هر جا با فرم کاربر طرف هستی، از Annotationهای مرتبط با UI و Validation در ViewModel استفاده کن.
اگر در پروژه از ViewModel استفاده میکنی، همهی Annotationهای مرتبط با فرم، اعتبارسنجی و نمایش UI باید در ViewModel باشن، و همهی Annotationهای مربوط به EF Core و دیتابیس باید فقط در Entity Model باقی بمونن.
| Annotation | ViewModel | Model | توضیح |
|---|---|---|---|
| [Required] | ✔️ | ✔️ | اعتبارسنجی الزامی بودن فیلد |
| [StringLength] | ✔️ | ✔️ | محدود کردن طول رشته (در فرم و در دیتابیس) |
| [RegularExpression] | ✔️ | ✔️ فقط در فرمها | اعتبارسنجی ساختار خاص مثل موبایل، کد ملی |
| [Compare] | ✔️ | ❌ | مقایسه بین دو فیلد (مثلاً رمز و تکرار) |
| [Display] | ✔️ | ✔️ برای UI | تغییر نام فیلد در رابط کاربری |
| [DataType] | ✔️ | ❌ | تعیین نوع ورودی برای فرمها (مثلاً ایمیل، تاریخ) |
| [UIHint] | ✔️ | ❌ | نمایش سفارشی فیلد با Template خاص |
| [HiddenInput] | ✔️ | ❌ | مخفیکردن فیلد در فرمها |
| [Key] | ❌ | ✔️ | تعیین کلید اصلی در جدول دیتابیس |
| [DatabaseGenerated] | ❌ | ✔️ | مشخص کردن نحوه تولید مقدار (Identity, Computed, None) |
| [ForeignKey] | ❌ | ✔️ | تنظیم کلید خارجی در رابطه بین موجودیتها |
| [NotMapped] | ❌ نیازی نیست | ✔️ | فیلدهایی که نباید در دیتابیس ذخیره شوند |
| [Timestamp] | ❌ | ✔️ | کنترل همزمانی رکوردها در EF Core |