ویرگول
ورودثبت نام
محمدرضا لامعی
محمدرضا لامعیبرنامه‌نویس، هکر و سایفرپانکی که به حریم خصوصی شما اهمیت می‌دهد! در این صفحه، با به اشتراک گذاشتن دانش و تجربه‌ام، به شما کمک می‌کنم تا از حریم خصوصی خود در برابر تهدیدات آنلاین محافظت کنید.
محمدرضا لامعی
محمدرضا لامعی
خواندن ۳ دقیقه·۱۰ ماه پیش

بررسی مکانیزم Relational Fixup در EF Core: تاثیر رهگیری (Tracking) ⚙️

در Entity Framework Core، مکانیزم Relational Fixup به فرآیند خودکار مقداردهی و اتصال Navigation Propertyها (مانند post.Blog یا blog.Posts) بین موجودیت‌ها (Entities) اشاره دارد که توسط یک نمونه DbContext یکسان رهگیری (Track) می‌شوند. 🔗

هدف اصلی این مکانیزم، حفظ سازگاری گراف اشیاء (Object Graph) در حافظه با روابط تعریف‌شده در پایگاه داده، برای موجودیت‌های رهگیری‌شده است.

نحوه عملکرد Relational Fixup (رفتار پیش‌فرض با رهگیری):

وقتی EF Core یک موجودیت را رهگیری می‌کند (از طریق کوئری‌های پیش‌فرض، Find(), Load(), Add(), Attach(), Update()), آن را در Change Tracker خود ثبت می‌کند. Change Tracker اطلاعات کلید اصلی (PK) و کلید خارجی (FK) را نگه می‌دارد.

Relational Fixup به عنوان بخشی از فرآیند رهگیری رخ می‌دهد:

  • یک موجودیت رهگیری می‌شود.
  • EF Core در Change Tracker خود جستجو می‌کند تا موجودیت(های) مرتبطِ از قبل رهگیری‌شده را (بر اساس PK/FK) پیدا کند.
  • اگر پیدا شوند، EF Core به طور خودکار Navigation Propertyهای هر دو طرف رابطه را مقداردهی می‌کند:Reference Navigation Property در موجودیت وابسته (مثلاً post.Blog) به موجودیت اصلیِ رهگیری‌شده اشاره می‌کند. ✅
    موجودیت وابسته به Collection Navigation Property در موجودیت اصلیِ رهگیری‌شده (مثلا به blog.Posts) اضافه می‌شود (اگر مجموعه null نباشد و مقداردهی اولیه شده باشد). ✅

مثال (با رهگیری - Fixup انجام می‌شود):

Blog با ID=1 رهگیری می‌شود
var blog = context.Blogs.Find(1);
Posts مرتبط با آن Blog لود و رهگیری می‌شوند
var posts = context.Posts.Where(p => p.BlogId == 1).ToList();
✅ Fixup خودکار انجام شده:
foreach(var post in posts)
{
post.Blog به شیء blog اشاره می‌کند
Console.WriteLine($"Post '{post.Title}' belongs to Blog '{post.Blog?.Url}'");
}
blog.Posts شامل اشیاء post لود شده است (اگر Posts مقداردهی اولیه شده باشد)
Console.WriteLine($"Blog '{blog.Url}' has {blog.Posts?.Count} posts.");

تأثیر AsNoTracking() (رفتار بدون Fixup): 🎯

اینجاست که تفاوت کلیدی مشخص می‌شود. وقتی شما از متد AsNoTracking() در کوئری‌های خود استفاده می‌کنید:

EF Core موجودیت‌های برگشتی از دیتابیس را رهگیری نمی‌کند. ❌

در نتیجه، این موجودیت‌ها وارد Change Tracker نمی‌شوند.

چون موجودیت‌ها رهگیری نمی‌شوند، مکانیزم Relational Fixup اصلاً اجرا نمی‌شود. 🚫

حتی اگر از Include() همراه با AsNoTracking() استفاده کنید، EF Core داده‌های مرتبط را در سطح SQL با هم JOIN می‌کند، اما در سطح اشیاء #C، هیچ تلاشی برای مقداردهی Navigation Propertyها انجام نمی‌دهد.

مثال (با AsNoTracking() - Fixup انجام نمی‌شود):

لود Blog و Posts بدون رهگیری
var blogNoTrack = context.Blogs
.Include(b => b.Posts) Include برای JOIN در SQL
.AsNoTracking() عدم رهگیری و عدم Fixup
.FirstOrDefault(b => b.BlogId == 1);
❌ Fixup انجام نشده:
if (blogNoTrack != null)
{
blogNoTrack.Posts احتمالا null یا خالی خواهد بود (بستگی به پیاده‌سازی دارد، اما EF Core آن را پر نکرده)
Console.WriteLine($"Blog (No Tracking) '{blogNoTrack.Url}' - Posts count: {blogNoTrack.Posts?.Count ?? 0}"); احتمالا 0 یا خطا اگر Posts null باشد
if (blogNoTrack.Posts != null)
{
foreach(var post in blogNoTrack.Posts)
{
post.Blog هم null خواهد بود، چون Fixup انجام نشده
Console.WriteLine($"Post '{post.Title}' - Blog reference is null: {post.Blog == null}"); // <- True
}
}
}

چه زمانی Relational Fixup (نوع با رهگیری) رخ می‌دهد؟ ⏱️

  • هنگام اجرای کوئری بدون AsNoTracking() (شامل Include() یا کوئری‌های جداگانه).
  • هنگام استفاده از Find().
  • هنگام استفاده از Load() برای بارگذاری صریح داده‌های مرتبط.
  • هنگام استفاده از Add(), Attach(), Update() روی موجودیت‌ها.

نکات کلیدی و پیش‌نیازها: 📝

  • رهگیری فعال: Fixup فقط برای موجودیت‌های رهگیری‌شده کار می‌کند. AsNoTracking() آن را غیرفعال می‌کند.
  • DbContext یکسان: همه موجودیت‌های مرتبط باید توسط یک نمونه DbContext رهگیری شوند.
  • مقداردهی اولیه مجموعه‌ها: برای اطمینان از اضافه شدن صحیح به مجموعه‌ها (مثل blog.Posts)، بهتر است آن‌ها را در سازنده کلاس مقداردهی اولیه کنید (= new List<Post>(); یا HashSet).

نتیجه‌گیری: ✨

Relational Fixup یک قابلیت مفید برای حفظ سازگاری روابط در موجودیت‌های رهگیری‌شده است. در مقابل، استفاده از AsNoTracking() با هدف افزایش پرفورمنس، هزینه عدم اجرای Fixup و عدم مقداردهی خودکار Navigation Propertyها را به همراه دارد. درک این تفاوت برای انتخاب روش مناسب کوئری زدن در سناریوهای مختلف ضروری است.

ef coreدات نتسی شارپ
۰
۰
محمدرضا لامعی
محمدرضا لامعی
برنامه‌نویس، هکر و سایفرپانکی که به حریم خصوصی شما اهمیت می‌دهد! در این صفحه، با به اشتراک گذاشتن دانش و تجربه‌ام، به شما کمک می‌کنم تا از حریم خصوصی خود در برابر تهدیدات آنلاین محافظت کنید.
شاید از این پست‌ها خوشتان بیاید