
آموزش پیشرفته Data Annotations در EF Core
در آموزش پیشرفته Data Annotations در Entity Framework Core، با یکی از راههای تعریف ویژگیها و تنظیمات مربوط به مدلها آشنا میشوید. ابتدا باید بدانید که مدلها همان کلاسهایی هستند که نماینده جدولها در دیتابیس هستند. در واقع، Data Annotationها یا همان حاشیهنویسیهای دادهای، Attributeهایی هستند که مستقیماً بالای کلاسها یا پراپرتیها نوشته میشوند. به این ترتیب، EF Core میتواند موارد زیر را تشخیص دهد:
- کدام پراپرتی کلید اصلی است.
- کدام فیلدها اجباری (Required) هستند و نمیتوانند خالی بمانند.
- طول مجاز فیلدهای متنی چقدر است.
- نام ستون یا جدول در دیتابیس چه باشد.
- ارتباط بین جداول (مانند رابطهی کلید خارجی) چگونه برقرار شود.
- و حتی کدام پراپرتی اصلاً نباید به دیتابیس تبدیل شود.
در نتیجه، این روش یک راه ساده، سریع و مستقیم برای تنظیم رفتار مدلهاست، بدون اینکه نیازی به استفاده از روش پیچیدهتر Fluent API داشته باشیم.
پرکاربردترین Data Annotation ها
برای شروع، بهتر است با پرکاربردترین Data Annotationها آشنا شوید. برای مثال، Attributeهایی مانند [Key] و [Required] ساختار اصلی مدل را مشخص میکنند. Attributeهایی مانند [StringLength] و [Range] برای تعیین محدودیتهای داده به کار میروند.
| Attribute | توضیح | مثال |
|---|---|---|
| [Key] | تعیین پراپرتی به عنوان کلید اصلی جدول | [Key] public int Id { get; set; } |
| [Required] | الزامی بودن فیلد (NULL نپذیرد) | [Required] public string Name { get; set; } |
| [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] public byte[] RowVersion; |
| [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 به نوع پراپرتی و نیاز پروژه بستگی دارد. بهعنوان مثال، [EmailAddress] برای بررسی ساختار ایمیل مناسب است؛ در حالی که [ForeignKey] رابطه میان موجودیتها را مشخص میکند. علاوه بر این، میتوان چند Data Annotation را بهصورت همزمان روی یک پراپرتی قرار داد.
Data Annotation های پیشرفته
در پروژههای بزرگتر، گاهی تنظیمات ساده کافی نیستند. در این شرایط، Data Annotationهای پیشرفته کنترل بیشتری روی فرمها و نحوه نمایش دادهها فراهم میکنند. از سوی دیگر، برخی از این Attributeها فقط به ASP.NET Core MVC مربوط هستند و ساختار دیتابیس را تغییر نمیدهند.
| Attribute | توضیح | مثال |
|---|---|---|
| [ScaffoldColumn(false)] | از نمایش این پراپرتی در صفحات Scaffold یا فرمهای خودکار جلوگیری میکند. | [ScaffoldColumn(false)] public string InternalCode { get; set; } |
| [BindNever] | از Bind شدن این فیلد به فرم ورودی جلوگیری میکند (مثلاً فیلدهای سیستمی). | [BindNever] public int AdminId { get; set; } |
| [BindRequired] | الزام میکند که فیلد حتماً مقداردهی شود هنگام Bind شدن. | [BindRequired] public string Username { get; set; } |
| [Display(Name = “…”)] | نام نمایشی برای فیلد در فرمها و رابط کاربری تعیین میکند. | [Display(Name = “Full Name”)] public string Name { get; set; } |
| [DisplayFormat] | فرمت نمایش داده برای فیلد (مثلاً تاریخ، پول، درصد). | [DisplayFormat(DataFormatString = “{0:yyyy-MM-dd}”, ApplyFormatInEditMode = true)] |
| [Editable(false)] | فیلد را فقط خواندنی (read-only) میکند در فرمها. | [Editable(false)] public string CreatedBy { get; set; } |
| [UIHint(“TemplateName”)] | برای استفاده از یک قالب (Template) سفارشی در فرمها. | [UIHint(“MultilineText”)] public string Notes { get; set; } |
| [HiddenInput(DisplayValue = false)] | نمایش فیلد به صورت input hidden در فرمها (ASP.NET MVC). | [HiddenInput(DisplayValue = false)] public int Id { get; set; } |
مزایای استفاده از Data Annotation
Data Annotation به توسعهدهنده اجازه میدهد تنظیمات مدل را مستقیماً در کلاسها و روی ویژگیها تعریف کند. بنابراین، کدنویسی سادهتر و سریعتر میشود و برای پروژههای سبک یا متوسط گزینه مناسبی است. همچنین، این روش ساختار واضحی دارد و برای افراد تازهکار بهراحتی قابل درک است. علاوه بر این، میتوان Data Annotation را در کنار Fluent API به کار برد تا تنظیمات جزئیتر و پیچیدهتر نیز انجام شوند. در نتیجه، توسعهدهنده میتواند از سادگی Data Annotation و امکانات کامل Fluent API بهصورت همزمان استفاده کند. برای مثال، Data Annotation مانند برچسبهایی است که مستقیماً روی دیوار میچسبانید تا به دیگران نشان دهید هر چیزی باید کجا قرار بگیرد. بنابراین، استفاده از آن سریع، ساده و واضح است.
- در نتیجه، کدنویسی ساده و سریع میشود و برای پروژههای سبک یا متوسط مناسب است.
- همچنین، این روش برای افراد تازهکار قابل درک است.
- علاوه بر این، میتوان از آن در کنار Fluent API برای تنظیمات جزئیتر استفاده کرد.
RegularExpression های پرکاربرد ایرانی
در ادامه، چند Regular Expression پرکاربرد برای بررسی اطلاعات ایرانی معرفی میکنیم. با استفاده از این الگوها میتوان ساختار شماره موبایل، کد ملی، کد پستی، شماره تلفن ثابت، شماره کارت بانکی و شماره شبا را بررسی کرد. همچنین، برای هر مورد یک مثال عملی ارائه میشود تا نحوه استفاده از آن در برنامهنویسی روشنتر باشد. البته Regular Expression فقط صحیح بودن ساختار ورودی را بررسی میکند؛ بنابراین، معتبر یا متعلق بودن اطلاعات به یک شخص واقعی را تأیید نمیکند.
| مورد | کد کامل Data Annotation |
|---|---|
| شماره موبایل ایران | [RegularExpression(@”^09\d{9}$”, ErrorMessage = “شماره موبایل باید با ۰۹ شروع شود و دقیقاً ۱۱ رقم باشد.”)] |
| شماره تلفن ثابت ایران | [RegularExpression(@”^0[1-8]{1}[0-9]{1}[0-9]{8}$”, ErrorMessage = “شماره تلفن ثابت باید با ۰ و کد شهر شروع شود و ۱۱ رقم باشد.”)] |
| شماره کارت بانکی | [RegularExpression(@”^\d{16}$”, ErrorMessage = “شماره کارت بانکی باید دقیقاً ۱۶ رقم باشد.”)] |
| کد ملی ایران | [RegularExpression(@”^\d{10}$”, ErrorMessage = “کد ملی باید دقیقاً ۱۰ رقم باشد.”)] |
| شماره شناسنامه | [RegularExpression(@”^\d{1,10}$”, ErrorMessage = “شماره شناسنامه باید بین ۱ تا ۱۰ رقم باشد.”)] |
| کد پستی ایران | [RegularExpression(@”^\d{10}$”, ErrorMessage = “کد پستی باید دقیقاً ۱۰ رقم باشد.”)] |
| شناسه ملی شرکت | [RegularExpression(@”^\d{11}$”, ErrorMessage = “شناسه ملی شرکت باید دقیقاً ۱۱ رقم باشد.”)] |
| شماره حساب بانک ملت | [RegularExpression(@”^\d{13}$”, ErrorMessage = “شماره حساب باید دقیقاً ۱۳ رقم باشد.”)] |
| ایمیل با دامنه .ir | [RegularExpression(@”^[\w\.-]+@[\w\.-]+\.(ir)$”, ErrorMessage = “ایمیل باید دارای دامنه .ir باشد.”)] |
| فقط حروف فارسی | [RegularExpression(@”^[آ-ی\s]+$”, ErrorMessage = “لطفاً فقط از حروف فارسی استفاده کنید.”)] |
| حروف و اعداد فارسی | [RegularExpression(@”^[آ-ی۰-۹\s]+$”, ErrorMessage = “فقط حروف و اعداد فارسی مجاز است.”)] |
| شماره پلاک خودرو | [RegularExpression(@”^\d{2}[آ-ی]\d{3}-\d{2}$”, ErrorMessage = “شماره پلاک باید به صورت ۱۲الف۳۴۵-۶۷ باشد.”)] |
مثال عملی Data Annotations
اکنون میتوان Data Annotationهای معرفیشده را در یک مثال کامل مشاهده کرد. ابتدا Attributeهای مربوط به دیتابیس روی مدل قرار میگیرند. سپس، Attributeهای اعتبارسنجی و نمایش به پراپرتیهای مربوط اضافه میشوند.
```csharp
[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 در مدل و ViewModel
ابتدا باید توجه کرد که از 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 استفاده کنید. در مقابل، هر جا با فرم کاربر طرف هستید، باید از انوتیشن های مرتبط با UI و Validation در ViewModel استفاده کنید.
اگر در پروژه از ViewModel استفاده میکنید. همه انوتیشن های مرتبط با فرم، اعتبارسنجی و نمایش UI باید در ViewModel باشند. همچنین، همه انوتیشن های مربوط به EF Core و دیتابیس باید فقط در Entity Model باقی بمانند.
lass=”table-responsive”></tr></tr><td>✔️✔️محدود کردن طول رشته (در فرم و در دیتابیس)<td>✔️❌مقایسه بین دوفیلد (مثلاً رمز و تکرار)<td>اعتبارسنجی الزامی بودن فیلد<tr>[StringLength]
| Annotation | ViewModel | Model | توضیح |
|---|---|---|---|
| [Required] | ✔️ | ✔️ | |
| [RegularExpression] | ✔️ | ✔️ | اعتبارسنجی ساختار خاص مثل موبایل، کد ملی |
| [Compare] | |||
| [Display] | ✔️ | ✔️ | تغییر نام فیلد در رابط کاربری |
| [DataType] | ✔️ | ❌ | تعیین نوع ورودی برای فرمها (مثلاً ایمیل، تاریخ) |
| [UIHint] | ✔️ | ❌ | نمایش سفارشی فیلد با Template خاص |
| [HiddenInput] | ✔️ | ❌ | مخفیکردن فیلد در فرمها |
| [Key] | ❌ | ✔️ | تعیین کلید اصلی در جدول دیتابیس |
| [DatabaseGenerated] | ❌ | ✔️ | مشخص کردن نحوه تولید مقدار (Identity, Computed, None) |
| [ForeignKey] | ❌ | ✔️ | تنظیم کلید خارجی در رابطه بین موجودیتها |
| [NotMapped] | ❌ | ✔️ | فیلدهایی که نباید در دیتابیس ذخیره شوند |
| [Timestamp] | ❌ | ✔️ | کنترل همزمانی رکوردها در EF Core |































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