محتاجين نعمل Implement للـ Unit of work
دا الكلاس اللي بمثابة الـ Unit بتاعنا للـ Work مع الـ Database من خلال الـ DbContext
لما بشتغل مع الـ Generic Repository عملنا الـ Add, Update, Delete والمفروض نعمل SaveChanges
وهو كل مرة هيعمل SaveChanges
وهتبقا أكتر من مرة
فأنا عايزة يعملها مرة واحدة بس انا مليش Access على الـ DbContext
Implementation
Interface
نروح في الـ Core ومش فأي فولدر ونعمل Interface بنعمل Property Signature for each and every repository بعرفهم على حسب أنا عندي كام table
public interface IUnitOfWork : IAsyncDsiposable
{
prop IGenericRepository<Product> ProductsRepo {get; set;}
prop IGenericRepository<ProductBrand> BrandsRepo {get; set;}
prop IGenericRepository<Product> ProductRepository {get; set;}
prop IGenericRepository<Product> ProductRepository {get; set;}
prop IGenericRepository<Product> ProductRepository {get; set;}
prop IGenericRepository<Order> OrdersRepo {get; set;}
Task<int> CompleteAsync();
}
خد بالك هنا انا معنديش Repository Specific لكل الحاجات دي عشان كدا بستخدم معاها الـ IGenericRepositry
بنعمل كمان الـ Method اللي بتحاكي الـ SaveChanges
و الـ Dispose اللي بنورثها من IDisposable
ممكن يبقا عندي أكتر من Unit of work لو انا عندي أكتر من Repository Layer ودا بيبقا لو عندي أكتر من DbContext ودي برضو بتكون لو عندي أكتر من Database
Class
في الـ Repository نعمل الـ UnitOfWork
ممكن الـ Cs Properties دي اما Full Property لو انا عايز يبقا ليا Access على الـ Attribute أو Automatic لو مش عايز يبقا ليا Access
تركاية: ممكن تاخد الجزء المتكرر وتعمل Replace لـ {get; set;}
public class UnitOfWork : IUnitOfWork
{
prop IGenericRepository<Product> ProductsRepo {get; set;}
prop IGenericRepository<ProductBrand> BrandsRepo {get; set;}
prop IGenericRepository<Product> ProductRepository {get; set;}
prop IGenericRepository<Product> ProductRepository {get; set;}
prop IGenericRepository<Product> ProductRepository {get; set;}
prop IGenericRepository<Order> OrdersRepo {get; set;}
// Ask CLR for Creating Object from DbContext Implicitly
public UnitOfWork(storeContext dbContext)
{
_dbContext = dbContext;
}
Task<int> CompleteAsync(StoreContext dbContext)
{
}
public ValueTask DisposeAsync()
{
}
}
الـ DbContext هو الكلاس اللي مسئول عن التعامل مع الـ Database
والـ Unit of Work هو الكلاس اللي مسئول عن التعامل مع الـ Database من خلال الـ DbContext فهيكون عنده Complete اللي هي SaveChanges
والـ Dispose اللي بتعمل Dispose
نروح لأي حد بيكلم الـ Generic Repository
فبدل ما اعمل Ask لـ Object بيعمل Implement لـ IGenericRepository
للبروداكت وواحد للميثود وواحد للأوردر
هعمل Implement للـ Class بتاع الـ UnitOfWork
وهتلاقي فيه الـ DbContext فيعمله برضو
// This is not in Unit of work
private readonly IBasketRepository _basketRepo;
private readonly IGenericRepository<Product> _productsRepo;
private readonly IGenericRepository<DeliveryMethod> _deliveryMethodsRepo;
private readonly IGenericRepository<Order> _ordersRepo;
وفي الـ Unit of work هيعمل من كل الـ IGenericRepository
اللي فيه، هيعمل Object بس هيبقا فاضي
فلازم في الكلاس نعمله Initialization
public class UnitOfWork : IUnitOfWork
{
prop IGenericRepository<Product> ProductsRepo {get; set;}
prop IGenericRepository<ProductBrand> BrandsRepo {get; set;}
prop IGenericRepository<Product> ProductRepository {get; set;}
prop IGenericRepository<Product> ProductRepository {get; set;}
prop IGenericRepository<Product> ProductRepository {get; set;}
prop IGenericRepository<Order> OrdersRepo {get; set;}
// Ask CLR for Creating Object from DbContext Implicitly
public UnitOfWork(storeContext dbContext)
{
_dbContext = dbContext;
ProductsRepo = new GenericRepository<Product>(_dbContext);
BrandsRepo = new GenericRepository<ProductBrand>(_dbContext);
CategoriesRepo = new GenericRepository<ProductCategory>(_dbContext);
DeliveryMethodsRepo = new GenericRepository<DeliveryMethod>(_dbContext);
OrderItemsRepo = new GenericRepository<OrderItem>(_dbContext);
OrdersRepo = new GenericRepository<Order>(_dbContext);
}
Task<int> CompleteAsync(StoreContext dbContext)
{
}
public ValueTask DisposeAsync()
{
}
}
بس الحل دا غلط لأني دايما لما هكلمه هيعمل Object فيه كل الـ Repositories بس المفروض أعمل Create لكل واحدة لما يتطلب بس
فالمفروض امسح دا والحل اني اسيبها زي ما هي وهتبقا بـ Null ولما احتاج حاجة اعمل Object واحطه فيها
بس احنا مش هنعمل الحل اللي فوق دا بس دلوقتي ممكن نعمل Array برضو، زي مثلًا لو عندي 5 أرقام فالأحسن اخزنها في Array
فنروح نعدل الـ Interface بتاعنا هنعمل فيها Method لما يطلب Generic Repository من الـ Order يروح يعملهاله وهكذا
public interface IUnitOfWork : IAsyncDisposable
{
IGenericRepository<TEntity> Repository<TEntity>() where TEntity : BaseEntity;
Task<int> CompleteAsync();
}
نروح نعملها Implement في الـ Class
public IGenericRepository<TEntity> Repository<TEntity>() where TEntity : BaseEntity
{
}
المفروض لو نده على الكلاس دي مثلًا Repository<Order>
فهي هترجعله object من كلاس الـ Generic Repository بتاع الـ Order
جه بعدها بشوية في نفس الكود او الريكويست طلب برضو نفس الحوار فهيعمل واحد جديد، بس كدا مش منطقي
فأنا محتاج أخزن الـ Object اللي يطلبه عشان لو طلبه مرة كمان أرجعهوله
فالحل اني اعمل Cs Generic List & Dictionary وهو عبارة عن Key, Value
الـ Key هتبقا String وهي اسم نوع الـ Repository
والـ Value هتكون GenericRepository
private Dictionary<string, GenericRepository<BaseEntity>> _repositories;
والمفروض أعمل Initialize واحطه في الـ Ctor لأنه اول ما ينادي على الـ Unit of Work معناها انه عايز يعمل Repostiories
// class
private Dictionary<string, GenericRepository<BaseEntity>> _repositories;
// ctor
public UnitOfWork(StoreContext dbContext)
{
_dbContext = dbContext;
_repositories = new Dictionary<string, GenericRepository<BaseEntity>>();
}
public IGenericRepository<TEntity> Repository<TEntity>() where TEntity : BaseEntity
{
var key = typeof(TEntity).Name; // Order
if(!_repositories.ContainsKey(key))
{
var repository = new GenericRepository<TEntity>(_dbContext) as GenericRepository<BaseEntity>;
_repositories.Add(key, repository);
}
return _repositories[key] as GenericRepository<TEntity>;
}
ممكن استخدم Hashtable
واريح نفسي من اني اعمل Casting كل شوية لأنها معمولة قبل الـ Generic فهي زي الـ Dictionary بس الفكرة ان الـ Key, Value الاتنين بيبقوا Object
بس متستخدمش الـ Hashtable
لو هيحصل Boxing و Unboxing
private Hashtable _repositories;
public UnitOfWork(StoreContext dbContext)
{
_dbContext = dbContext;
_repositories = new Hashtable();
}
public IGenericRepository<TEntity> Repository<TEntity>() where TEntity : BaseEntity
{
var key = typeof(TEntity).Name; // Order
if(!_repositories.ContainsKey(key))
{
var repository = new GenericRepository<TEntity>(_dbContext);
_repositories.Add(key, repository);
}
return _repositories[key] as GenericRepository<TEntity>;
}
// Continue
public async Task<int> CompleteAsync()
=> await _dbContext.SaveChangesAsync();
public async ValueTask DisposeAsync()
=> await _dbContext.DisposeAsync();