- بواسطة x32x01 ||
بص يا صديقي… الموضوع بدأ معايا تقريبًا في مشروع e-commerce.
كان مشروع كبير، وفيه عمليات كتير بتحصل على الداتابيز كل ثانية.
في مرة من المرات
واحد من اليوزرز عمل Order جديد.
فأنا كمهندس محترم دخلت أضيف الـ Order… وهنا الكارثة حصلت.
أضفت الطلب، تمام.
جيت أقلل كمية المنتج من المخزون… حصل Error.
النتيجة؟
الـ Order اتسجّل، لكن كمية المنتج مقلتش.
يعني الداتا باظت
وبقينا في وضع "هو اشترى حاجة مش موجودة أصلاً"
وساعتها فهمت إن الموضوع محتاج تنظيم بحت.
مش مجرد SaveChanges() وخلاص.
لا… الموضوع محتاج نظام يضمن إن العملية كلها يا تتم صح… يا متحصلش من الأساس.
وهنا بيظهر بقى دور:
من كود مكركب…
لكود راقي، منظم، سهل تتغير فيه أي حاجة بعدين
إنت عندك شغل كتير هيتعمل في الداتابيز:
إضافة Order → تعديل Product → تسجيل Payment
Unit of Work بيجمع العمليات دي كلها في Transaction واحدة.
يعني:
زي ما بنقول في الكورة:
يا goal… يا بلّاها
كده إحنا بنعمل SaveChanges في كل خطوة.
وده خطر جدًا.
مع Unit of Work بقى:
لو أي خطوة ضربت؟
Rollback يرجع كل شيء زي ما كان
إنت كده بتربط الكود كله بـ Entity Framework وربطه بالداتابيز نفسها.
يعني:
الـ Repository بقى بيعمل طبقة وسيطة…
بيخلي الكود بتاعك يتعامل مع:
مش مع DbContext مباشرة.
بالتالي:
طب إزاي نجمعهم مع بعض؟ (الجمال كله هنا
كده السيناريو يبقى جميل جدًا
كود نظيف
سهل يتقرى
سهل يتعدل
ومفيش داتا هتباظ تاني
أيوه… صح
الـ DbContext في EF Core يعتبر Unit of Work
والـ DbSet يعتبر Repository
لكن…
لو استخدمتهم مباشرة في الـ business logic:
إنت بتربط كل حاجة بالـ Entity Framework.
وده بيخليك مش عارف تختبر الكود بسهولة.
الـ Repository + Unit of Work مش مجرد تكرار…
هو Abstraction Layer
طبقة بتحمي الكود من التعقيد والتغيير.
الخلاصة
كان مشروع كبير، وفيه عمليات كتير بتحصل على الداتابيز كل ثانية.
في مرة من المرات
واحد من اليوزرز عمل Order جديد.
فأنا كمهندس محترم دخلت أضيف الـ Order… وهنا الكارثة حصلت.
أضفت الطلب، تمام.
جيت أقلل كمية المنتج من المخزون… حصل Error.
النتيجة؟
الـ Order اتسجّل، لكن كمية المنتج مقلتش.
يعني الداتا باظت
وبقينا في وضع "هو اشترى حاجة مش موجودة أصلاً"
وساعتها فهمت إن الموضوع محتاج تنظيم بحت.
مش مجرد SaveChanges() وخلاص.
لا… الموضوع محتاج نظام يضمن إن العملية كلها يا تتم صح… يا متحصلش من الأساس.
وهنا بيظهر بقى دور:
- Unit of Work
- Repository Pattern
من كود مكركب…
لكود راقي، منظم، سهل تتغير فيه أي حاجة بعدين
يعني إيه Unit of Work ببساطة؟
فكر فيها كده…إنت عندك شغل كتير هيتعمل في الداتابيز:
إضافة Order → تعديل Product → تسجيل Payment
Unit of Work بيجمع العمليات دي كلها في Transaction واحدة.
يعني:
- يا كله ينجح

- يا كله يتلغى

زي ما بنقول في الكورة:
يا goal… يا بلّاها
مثال بسيط يوضح الفكرة
بدون Unit of Work: C#:
var order = new Order { UserId = 1, Total = 500 };
context.Orders.Add(order);
context.SaveChanges();
var product = context.Products.First(p => p.Id == order.ProductId);
product.Stock -= 1;
context.SaveChanges();
// حصل Error هنا؟ الداتا اتباظت. وده خطر جدًا.
مع Unit of Work بقى:
C#:
unitOfWork.Orders.Add(order);
unitOfWork.Products.UpdateStock(order.ProductId, -1);
unitOfWork.Complete(); // هنا كل حاجة تتنفذ مع بعض Rollback يرجع كل شيء زي ما كان
طب وإيه بقى حكاية Repository Pattern؟
شوف… لما تيجي تتعامل مع الداتابيز مباشرة في كل مكان في المشروع: C#:
context.Users.Add();
context.Orders.Where();
context.Products.First(); يعني:
- لو غيرت ORM → عندك مصيبة

- لو عايز تختبر الكود بدون داتابيز → مستحيل تقريبًا
الـ Repository بقى بيعمل طبقة وسيطة…
بيخلي الكود بتاعك يتعامل مع:
C#:
IUserRepository
IOrderRepository
IProductRepository بالتالي:
- الكود بقى واضح
- سهل الاختبار
- سهل التعديل
- Decoupled جدًا
شكل Repository في C#
C#:
public interface IOrderRepository
{
Order GetById(int id);
void Add(Order order);
}
public class OrderRepository : IOrderRepository
{
private readonly AppDbContext _context;
public OrderRepository(AppDbContext context)
{
_context = context;
}
public Order GetById(int id) => _context.Orders.Find(id);
public void Add(Order order) => _context.Orders.Add(order);
} طب إزاي نجمعهم مع بعض؟ (الجمال كله هنا
)
C#:
public interface IUnitOfWork : IDisposable
{
IOrderRepository Orders { get; }
IProductRepository Products { get; }
IPaymentRepository Payments { get; }
int Complete();
}
public class UnitOfWork : IUnitOfWork
{
private readonly AppDbContext _context;
public IOrderRepository Orders { get; }
public IProductRepository Products { get; }
public IPaymentRepository Payments { get; }
public UnitOfWork(AppDbContext context,
IOrderRepository orders,
IProductRepository products,
IPaymentRepository payments)
{
_context = context;
Orders = orders;
Products = products;
Payments = payments;
}
public int Complete() => _context.SaveChanges();
public void Dispose() => _context.Dispose();
} كده السيناريو يبقى جميل جدًا
C#:
using (var uow = new UnitOfWork(new AppDbContext()))
{
uow.Orders.Add(order);
uow.Products.ReduceStock(order.ProductId, 1);
uow.Payments.Record(order.UserId, order.Total);
uow.Complete();
} سهل يتقرى
سهل يتعدل
ومفيش داتا هتباظ تاني
طب سؤال مهم:
هو مش DbContext نفسه بيعمل كده؟أيوه… صح
الـ DbContext في EF Core يعتبر Unit of Work
والـ DbSet يعتبر Repository
لكن…
لو استخدمتهم مباشرة في الـ business logic:
إنت بتربط كل حاجة بالـ Entity Framework.
وده بيخليك مش عارف تختبر الكود بسهولة.
الـ Repository + Unit of Work مش مجرد تكرار…
هو Abstraction Layer
طبقة بتحمي الكود من التعقيد والتغيير.
الخلاصة
| قبل | بعد |
|---|---|
| كود مكركب بيتعامل مع الداتابيز في كل مكان | كود منظم بيتعامل بـ Repositories |
| عمليات ممكن تبوظ الداتا بسهولة | Transaction واحدة تحميك |
| كود صعب يتعدل | كود سهل التطوير والتحديث |
| مستحيل تعمله Unit Test | سهل جدًا يتختبر |