سوالات مصاحبه Entity Framework در .NET
مقدمه
Entity Framework (EF) یک Object-Relational Mapping (ORM) فریمورک قدرتمند برای .NET است که توسعهدهندگان را قادر میسازد تا با پایگاههای داده با استفاده از اشیاء .NET کار کنند. درک عمیق EF برای هر توسعهدهنده .NET که با دادهها سروکار دارد، ضروری است.
سوال 1: Entity Framework چیست؟
پاسخ: Entity Framework (EF) یک ORM (Object-Relational Mapper) برای .NET است. این فریمورک به توسعهدهندگان اجازه میدهد تا با پایگاه دادهها با استفاده از اشیاء داتنت (C# یا VB.NET) به جای کوئریهای SQL مستقیم کار کنند. EF مسئول نگاشت (Mapping) بین اشیاء داتنت و جداول پایگاه داده است.
سوال 2: مزایای استفاده از Entity Framework چیست؟
- توسعه سریعتر: با کاهش نیاز به نوشتن کد دسترسی به دادهها، توسعه سریعتر میشود.
- کاهش خطاهای برنامهنویسی: با استفاده از اشیاء و بررسی نوع (Type Checking)، خطاهای مربوط به SQL کمتر میشود.
- قابلیت نگهداری بالاتر: کد تمیزتر و خواناتر است.
- استقلال از پایگاه داده: میتوان پایگاه داده را بدون تغییر کد برنامه تغییر داد.
- پشتیبانی از LINQ: امکان نوشتن کوئریهای قوی و نوعامن (Type-Safe) با استفاده از LINQ.
سوال 3: Code First، Model First و Database First در EF چه تفاوتهایی دارند؟
- Code First: شما ابتدا مدلهای دامنه (کلاسهای C#) را تعریف میکنید و EF بر اساس آنها پایگاه داده را ایجاد یا بهروزرسانی میکند. این رویکرد برای پروژههای جدید و توسعهدهندگانی که به کدنویسی شیءگرا علاقهمندند، مناسب است.
- Database First: شما ابتدا پایگاه داده را طراحی میکنید و EF بر اساس آن مدلهای دامنه و Context را تولید میکند. این رویکرد برای پروژههایی که پایگاه داده موجود دارند، مناسب است.
- Model First: شما مدل بصری (Visual Model) را در EF Designer طراحی میکنید و EF بر اساس آن پایگاه داده و کلاسهای مدل را تولید میکند. این رویکرد کمتر مورد استفاده قرار میگیرد.
سوال 4: Context در Entity Framework چیست؟
Context (یا DbContext) کلاس اصلی در Entity Framework است که نقش یک پل بین مدلهای دامنه شما و پایگاه داده را ایفا میکند. این کلاس مسئول موارد زیر است:
- مدیریت اتصال به پایگاه داده: نگهداری Connection String و باز و بسته کردن اتصالات.
- ردیابی تغییرات: پیگیری تغییراتی که روی اشیاء مدل انجام میشود (افزودن، ویرایش، حذف).
- ارسال کوئریها: تبدیل کوئریهای LINQ به SQL و ارسال آنها به پایگاه داده.
- ذخیره تغییرات: ارسال تغییرات ردیابی شده به پایگاه داده (Save Changes).
- مدیریت DbSet: هر DbSet در Context نماینده یک جدول در پایگاه داده است.
سوال 5: DbSet در Entity Framework چیست؟
DbSet یک کلاس در Entity Framework است که نماینده یک مجموعه از موجودیتها (Entities) در Context است. هر DbSet به یک جدول خاص در پایگاه داده نگاشت میشود. شما از DbSet برای انجام عملیات CRUD (Create, Read, Update, Delete) روی موجودیتها استفاده میکنید. به عنوان مثال، DbSet<Product> Products { get; set; }
یک DbSet برای موجودیت Product ایجاد میکند که به جدول Products در پایگاه داده نگاشت میشود.
سوال 6: تفاوت بین Lazy Loading و Eager Loading در EF چیست؟
- Lazy Loading (بارگذاری تنبل): به صورت پیشفرض فعال است. دادههای مرتبط (مثلاً لیست سفارشات یک مشتری) تنها زمانی از پایگاه داده بارگذاری میشوند که برای اولین بار به آنها دسترسی پیدا کنید. این میتواند باعث ایجاد کوئریهای N+1 شود (یعنی برای هر موجودیت اصلی، یک کوئری جداگانه برای دادههای مرتبط ارسال میشود).
- Eager Loading (بارگذاری مشتاق): دادههای مرتبط به صورت همزمان با موجودیت اصلی بارگذاری میشوند. این کار با استفاده از متدهای Include() در LINQ انجام میشود. Eager Loading تعداد کوئریهای ارسال شده به پایگاه داده را کاهش میدهد و عملکرد را بهبود میبخشد، به خصوص زمانی که میدانید به دادههای مرتبط نیاز خواهید داشت.
سوال 7: Migration در EF Core چیست و چرا از آن استفاده میشود؟
Migration در EF Core ابزاری است که به شما اجازه میدهد تا تغییرات مدل دامنه (کلاسهای C#) خود را به اسکیما (Schema) پایگاه داده اعمال کنید. با هر تغییر در مدل، یک Migration جدید ایجاد میکنید که شامل کدهای لازم برای بهروزرسانی پایگاه داده است. مزایای آن عبارتند از:
- مدیریت تغییرات پایگاه داده: به شما کمک میکند تا تغییرات پایگاه داده را به صورت کنترل شده و نسخهبندی شده مدیریت کنید.
- توسعه تیمی: امکان همکاری آسانتر در پروژههایی که چندین توسعهدهنده روی مدل و پایگاه داده کار میکنند.
- استقرار آسان: بهروزرسانی پایگاه داده در محیطهای مختلف (توسعه، تست، تولید) را ساده میکند.
سوال 8: چگونه یک Migration جدید در EF Core ایجاد کنیم؟
برای ایجاد یک Migration جدید، از دستور زیر در Package Manager Console (در Visual Studio) یا Command Line Interface (CLI) استفاده میکنید:
Add-Migration [MigrationName]
یا در CLI:
dotnet ef migrations add [MigrationName]
[MigrationName]
یک نام توصیفی برای Migration شماست (مثلاً AddProductsTable
).
سوال 9: چگونه Migration را به پایگاه داده اعمال کنیم؟
برای اعمال Migration به پایگاه داده، از دستور زیر در Package Manager Console یا CLI استفاده میکنید:
یا در CLI:
dotnet ef database update
این دستور تمام Migrationهای اعمال نشده را به ترتیب به پایگاه داده اعمال میکند.
سوال 10: تفاوت بین Tracking و No-Tracking در EF چیست؟
- Tracking (ردیابی): به صورت پیشفرض فعال است. EF تغییراتی که روی موجودیتهای بارگذاری شده از پایگاه داده انجام میدهید را ردیابی میکند. وقتی SaveChanges() را فراخوانی میکنید، EF این تغییرات را به پایگاه داده اعمال میکند. این برای سناریوهایی که قصد ویرایش یا حذف دادهها را دارید، مناسب است.
- No-Tracking (عدم ردیابی): EF تغییرات روی موجودیتها را ردیابی نمیکند. این برای سناریوهایی که فقط قصد خواندن دادهها را دارید و نمیخواهید آنها را تغییر دهید، مناسب است. استفاده از No-Tracking میتواند عملکرد را بهبود بخشد، زیرا EF نیازی به نگهداری وضعیت موجودیتها ندارد. برای فعال کردن No-Tracking از متد AsNoTracking() استفاده میکنید.
سوال 11: چگونه یک موجودیت را در EF Core اضافه کنیم؟
برای اضافه کردن یک موجودیت جدید، ابتدا یک نمونه از کلاس موجودیت ایجاد میکنید، سپس آن را به DbSet مربوطه اضافه کرده و در نهایت SaveChanges() را فراخوانی میکنید:
var newProduct = new Product { Name = "Laptop", Price = 1200 };
_context.Products.Add(newProduct);
_context.SaveChanges();
سوال 12: چگونه یک موجودیت را در EF Core ویرایش کنیم؟
برای ویرایش یک موجودیت، ابتدا آن را از پایگاه داده بارگذاری میکنید، تغییرات لازم را اعمال میکنید و سپس SaveChanges() را فراخوانی میکنید. EF به صورت خودکار تغییرات را ردیابی میکند:
var productToUpdate = _context.Products.Find(1);
if (productToUpdate != null)
{
productToUpdate.Price = 1250;
_context.SaveChanges();
}
سوال 13: چگونه یک موجودیت را در EF Core حذف کنیم؟
برای حذف یک موجودیت، ابتدا آن را از پایگاه داده بارگذاری میکنید، سپس آن را از DbSet مربوطه حذف کرده و در نهایت SaveChanges() را فراخوانی میکنید:
var productToDelete = _context.Products.Find(1);
if (productToDelete != null)
{
_context.Products.Remove(productToDelete);
_context.SaveChanges();
}
سوال 14: Data Annotations و Fluent API در EF Core چه کاربردی دارند؟
- Data Annotations: ویژگیهایی (Attributes) هستند که میتوانید به کلاسها و Propertyهای مدل خود اضافه کنید تا قوانین نگاشت (Mapping) و اعتبارسنجی (Validation) را تعریف کنید. مثلاً
[Required]
، [MaxLength(50)]
.
- Fluent API: یک روش کدنویسی برای پیکربندی مدل EF است که انعطافپذیری بیشتری نسبت به Data Annotations فراهم میکند. از آن برای تعریف نگاشتهای پیچیده، روابط و محدودیتها استفاده میشود.
سوال 15: Unit of Work و Repository Pattern در EF Core چه هستند و چرا از آنها استفاده میکنیم؟
Unit of Work و Repository Pattern دو الگوی طراحی هستند که برای بهبود معماری و قابلیت تستپذیری برنامههای مبتنی بر Entity Framework استفاده میشوند:
- Repository Pattern: یک لایه انتزاع بین منطق کسبوکار و لایه دسترسی به دادهها ایجاد میکند. این الگو عملیات CRUD را در یک رابط واحد کپسوله میکند و امکان تستپذیری و جایگزینی پیادهسازی را فراهم میکند.
- Unit of Work: مجموعهای از تغییرات را که باید به صورت اتمیک (Atomic) انجام شوند، مدیریت میکند. این الگو تضمین میکند که تمام تغییرات یا به طور کامل اعمال شوند یا هیچکدام اعمال نشوند.
مزایا:
- تستپذیری بهتر: امکان Mock کردن Repository ها
- جداسازی نگرانیها: منطق کسبوکار از جزئیات دسترسی به دادهها جدا میشود
- قابلیت نگهداری: تغییرات در لایه داده کمتر بر سایر بخشها تأثیر میگذارد
سوال 16: Shadow Properties در EF Core چیست؟
Shadow Properties ویژگیهایی در مدل EF Core هستند که در کلاسهای داتنت شما تعریف نمیشوند، اما در مدل EF و در پایگاه داده وجود دارند. این ویژگیها معمولاً برای ذخیره دادههای فرادادهای (Metadata) یا دادههایی که نیازی به نمایش در مدل دامنه ندارند، استفاده میشوند. به عنوان مثال، میتوانید یک Shadow Property برای LastUpdatedDate
تعریف کنید که به صورت خودکار توسط EF بهروزرسانی شود، بدون اینکه نیاز باشد این Property در کلاس مدل شما وجود داشته باشد.
سوال 17: Change Tracking در EF Core چگونه کار میکند؟
Change Tracking مکانیزمی است که EF Core برای ردیابی تغییرات اعمال شده بر روی موجودیتها استفاده میکند. این مکانیزم شامل موارد زیر است:
- Snapshot Change Tracking: EF یک عکسفوری (Snapshot) از وضعیت اولیه موجودیت نگه میدارد و هنگام فراخوانی SaveChanges()، وضعیت فعلی را با عکسفوری مقایسه میکند.
- Change Detection: EF تغییرات را شناسایی کرده و SQL مناسب برای اعمال تغییرات تولید میکند.
- Entity States: هر موجودیت یکی از حالتهای Added، Modified، Deleted، Unchanged یا Detached را دارد.
سوال 18: Connection Pooling در EF Core چیست؟
Connection Pooling تکنیکی است که EF Core برای بهبود عملکرد از آن استفاده میکند. به جای ایجاد و بستن اتصال پایگاه داده برای هر درخواست، EF یک مجموعه (Pool) از اتصالات از پیش ایجاد شده نگه میدارد. مزایای آن عبارتند از:
- کاهش زمان پاسخ: عدم نیاز به ایجاد اتصال جدید برای هر درخواست
- بهبود عملکرد: کاهش overhead ایجاد و بستن اتصالات
- مدیریت منابع بهتر: کنترل تعداد اتصالات همزمان به پایگاه داده
برای فعال کردن Connection Pooling از متد AddDbContextPool استفاده میشود.
سوال 19: Global Query Filters در EF Core چیست؟
Global Query Filters امکانی است که به شما اجازه میدهد فیلترهای خودکار را بر روی موجودیتها اعمال کنید. این فیلترها به صورت خودکار به تمام کوئریهایی که شامل آن موجودیت هستند، اضافه میشوند. کاربردهای رایج آن عبارتند از:
- Soft Delete: مخفی کردن رکوردهای حذف شده
- Multi-tenancy: فیلتر کردن دادهها بر اساس Tenant
- Security: محدود کردن دسترسی به دادهها بر اساس کاربر
برای تعریف Global Query Filter از متد HasQueryFilter در OnModelCreating استفاده میشود.
سوال 20: Owned Types در EF Core چیست؟
Owned Types نوعی از موجودیتها در EF Core هستند که نمیتوانند به صورت مستقل وجود داشته باشند و همیشه به عنوان بخشی از یک موجودیت اصلی در نظر گرفته میشوند. این نوع موجودیتها معمولاً برای نمایش Value Objects در Domain-Driven Design استفاده میشوند. مثالهای رایج شامل آدرس، مختصات جغرافیایی یا اطلاعات تماس هستند.
ویژگیهای کلیدی:
- عدم استقلال: نمیتوانند بدون موجودیت مالک وجود داشته باشند
- مدیریت چرخه حیات: چرخه حیات آنها توسط موجودیت مالک کنترل میشود
- نگاشت انعطافپذیر: میتوانند در همان جدول یا جداول جداگانه ذخیره شوند