A professional developer never calls _context.SaveChanges() directly in their controller. They use these architectural patterns to decouple the data access from their business logic.
The Repository acts as a mediator between the application and the data store. It encapsulates the logic required to access data.
What if your operation involves multiple repositories? (e.g., Creating an Order and Updating Inventory). If one fails, Both must fail. This is where Unit of Work comes in.
// The Unit of Work Interface (Expert Setup)
public interface IUnitOfWork : IDisposable {
IUserRepository Users { get; }
IOrderRepository Orders { get; }
Task CompleteAsync(); // Effectively calls db.SaveChangesAsync()
}
// Why it's useful:
var order = new Order { ... };
_uow.Orders.Add(order);
_uow.Users.UpdatePoints(userId, 10);
await _uow.CompleteAsync(); // Both operations are saved in one transaction
Senior architects often implement a Generic Repository IRepository<T> to handle common CRUD (Create, Read, Update, Delete) operations for all entities. This reduces boilerplate code by **90%** and ensures consistent data access across the entire enterprise application.