اگر EF Core خودش Repository Pattern را ارائه میدهد، چرا باید یک abstraction دیگر روی آن بسازیم؟ 🤔📦یکی از بحثهای همیشگی در جامعهی .NET این است:
آیا هنوز باید از الگوهای Repository و Unit of Work استفاده کنیم، یا این الگوها در برنامههای مدرن منسوخ شدهاند یا حتی مضر هستند؟
بههرحال، اگر روی DbContext در EF Core hover کنید، مایکروسافت بهوضوح میگوید:
A DbContext instance represents a session with the database and is a combination of the Unit of Work and Repository patterns.
این یعنی EF Core همین حالا این الگوها را پیادهسازی میکند:
• ءDbContext نقش Unit of Work را بازی میکند
• ء<DbSet<TEntity نقش Repository را ایفا میکند
پس سؤال طبیعی این است:
وقتی EF Core همین حالا این abstractions را فراهم میکند، چرا باید یک abstraction دیگر روی آن بسازیم — یعنی یک «abstraction روی abstraction»؟ 🧱🧱
بسیاری از توسعهدهندگان همچنین معتقدند نوشتن repositoryهای سفارشی باعث میشود قابلیتهای قدرتمند EF Core از دید پنهان شود، مانند:
• Eager Loading
• AsNoTracking
• Projections
• Query Composition
• Global Query Filters
• Split Queries
بازنویسی همهی اینها داخل Repositoryهای custom معمولاً به یک نتیجه منتهی میشود:
«ما فقط داریم DbContext را دوباره اختراع میکنیم، فقط با قدمهای اضافی.» 🔁🙃
یک استدلال رایج دیگر testability است.
برخی میگویند برای تستهای واحد باید repository داشته باشیم تا بتوانیم DbContext را mock کنیم؛ اما EF Core همین حالا یک InMemory provider عالی دارد که تستها را واقعیتر میکند و نیاز به mock کردن کل لایهی persistence را از بین میبرد. 🧪🚫
و سپس یک ترس دیگر هم وجود دارد:
«شاید یک روز ORM را عوض کنیم.»
اما در ۹۹٪ پروژههای واقعی این اتفاق نمیافتد.
و حتی اگر هم بیفتد، تغییر فقط repository interfaceها را شامل نمیشود، بلکه بخشهای بسیار بیشتری از سیستم را لمس خواهد کرد — پس این استدلال عمدتاً یک نقض آشکارِ YAGNI است. ⚠️🧠
البته هر Repository اضافی که ایجاد میکنید، سربار نگهداری را افزایش میدهد:
کلاسهای بیشتر 📦
اینترفیسهای بیشتر 🧩
ساختارهای اتصال بیشتر 🔌
پیچیدگی بیشتر 🧠
پس… آیا Repository Pattern مضر است؟ یا ما آن را اشتباه استفاده میکنیم؟
واقعیت، ظریفتر از این حرفهاست.
بسیاری از نظرات منفی ناشی از سوءبرداشت از هدف Repository هستند.Repository هرگز قرار نبود تمام قابلیتهای persistence framework را در معرض دید قرار دهد.
هدف آن این نیست که API مربوط به DbContext را بازتولید کند.
وظیفهٔ اصلی آن این است که کنترل کند دامنه چگونه با داده تعامل میکند.
🎯 Repository واقعاً چه هدفی دارد؟
بهجای ارائهٔ یک سطح دسترسی باز و نامحدود به داده، Repository یک سری عملیات Aggregate-focused، صریح، و intention-revealing تعریف میکند.
این کار چند مزیت مهم به همراه دارد:
منطق کوئری قابلپیشبینی و قابل نگهداری
رفتار کوئری ثابت و در طول زمان بهینهتر میشود.
شفافیت برای domain expertها
نام متدها هدف و مفهوم تجاری را بیان میکنند؛ نیازی نیست SQL یا LINQ بلد باشند.
عملیات دامنهمحور بهجای CRUD عمومی
بهجای اینکه هر نوع دستکاری entity را در اختیار بگذارد، رفتارهایی ارائه میدهد که واقعاً برای دامنه معنادار است.
🛡 هدف واقعی: محافظت از Domain Model
ءRepository pattern در درجهٔ اول دربارهٔ اینها نیست:
• آسانتر کردن unit testing
• امکان تعویض Database
• بستهبندی امکانات EF Core
هدف اصلی آن این است که Domain Model را از نشت نگرانیهای persistence محافظت کند.
در غیاب یک مرز Repository، منطق persistence دیر یا زود وارد دامنه میشود، وضوح را کاهش میدهد، coupling را افزایش میدهد، و مدل را تضعیف میکند.
⛔️ چه زمانی نباید از Repository استفاده کنید؟
• زمانی که دامنهٔ شما ساده است
• زمانی که CRUD کافی است
• زمانی که میخواهید از قابلیتهای EF Core بهصورت مستقیم استفاده کنید
در این موارد، Repository فقط پیچیدگی غیرضروری اضافه میکند.
✅ و چه زمانی باید از Repository استفاده کنید؟
• وقتی با یک دامنهٔ پیچیده و غنی از رفتار سروکار دارید
در چنین سیستمهایی، Repository تبدیل به بخشی از دامنه میشود، قدرت بیان مدل را افزایش میدهد و مرزهای Aggregate را تقویت میکند.
✨ جمعبندی
ءRepository pattern ضدالگو نیست
استفادهٔ اشتباه از آن ضدالگوست.
وقتی آگاهانه و در دامنههای غنی و پیچیده بهکار گرفته شود، به ابزاری قدرتمند برای بیان intent تجاری و حفظ یک معماری تمیز و مقاوم تبدیل میشود.
ساده نگهش دارید.
📌Daniel Jajimi
🔖هشتگها:
#DDD #CleanArchitecture #RepositoryPattern #SoftwareArchitecture #AggregateDesign