Ho creato un'applicazione (core core 2 & ef core) con pattern Unit Of Work e Generic repository. Avevo un solo contesto di database, ma a causa di alcune logiche di business ho dovuto creare un secondo database con alcune stesse entità.
Per semplicità, userò solo una Entity, la ProductEntity
e userò solo 1 metodo repository the Get by Id
.
Nella logica aziendale devo essere in grado di recuperare il Prodotto dai due contesti, fare alcune cose e quindi aggiornare i contesti, ma con un design UoW pulito.
Il repository è implementato in questo modo
public interface IRepository<TEntity>
where TEntity : class, new()
{
TEntity Get(int id);
}
public interface IProductsRepository : IRepository<ProductEntity>
{
}
public class ProductsRepository : Repository<ProductEntity>, IProductsRepository
{
public ProductsRepository(DbContext context) : base(context)
{
}
}
Implementazione di UOW con un contesto db
public interface IUnitOfWork : IDisposable
{
IProductsRepository ProductsRepository { get; }
int Complete();
}
public class UnitOfWork : IUnitOfWork
{
private readonly DbContext _context;
public UnitOfWork(MainContext context)
{
// injecting the main database
_context = context;
}
private IProductsRepository _productsRepository;
public IProductsRepository ProductsRepository => _productsRepository ?? (_productsRepository = new ProductsRepository(_context));
public int Complete()
{
return _context.SaveChanges();
}
public void Dispose()
{
_context?.Dispose();
}
}
Sto usando il framework predefinito di .NET Core per DI, quindi nel mio file Startup.cs
ho il seguente
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// ...
// main database
services.AddDbContext<MainContext>(options => options.UseSqlServer(Configuration.GetConnectionString("MainDatabaseConnection"), providerOptions => providerOptions.CommandTimeout(30)));
// unit of work
services.AddTransient<IUnitOfWork, UnitOfWork>();
}
Per risolvere il problema ho creato un secondo UnitOfWork con contesto hardcoded e sto usando le stesse entità / repository
La mia implementazione con due contesti db
public interface IUnitOfWorkSecondary : IDisposable
{
IProductsRepository ProductsRepository { get; }
int Complete();
}
public class UnitOfWorkSecondary : IUnitOfWorkSecondary
{
private readonly DbContext _context;
public UnitOfWork(SecondaryDatabaseContext context)
{
// injecting the secondary database
_context = context;
}
// same as above
}
Quindi in un oggetto aziendale sto facendo il seguente
public class Program
{
private readonly IUnitOfWork _unitOfWork;
private readonly IUnitOfWorkSecondary _unitOfWorkSecondary;
public Program(IUnitOfWork unitOfWork, IUnitOfWorkSecondary unitOfWorkSecondary){
_unitOfWork = unitOfWork;
_unitOfWorkSecondary = unitOfWorkSecondary;
}
public static void Method1(int productId)
{
var mainProduct = _unitOfWork.ProductsRepository.Get(productId);
var secondaryProduct = _unitOfWorkSecondary.ProductsRepository.Get(productId);
mainProduct.Name = "Hello Main";
secondaryProduct.Name = "Hello Secondary";
_unitOfWork.Complete();
_unitOfWorkSecondary.Complete();
}
}
Il Startup.cs
viene modificato in
// main database
services.AddDbContext<MainContext>(options => options.UseSqlServer(Configuration.GetConnectionString("MainDatabaseConnection"), providerOptions => providerOptions.CommandTimeout(30)));
// secondary database
services.AddDbContext<SecondaryContext>(options => options.UseSqlServer(Configuration.GetConnectionString("SecondaryDatabaseConnectiont"), providerOptions => providerOptions.CommandTimeout(30)));
// unit of work
services.AddTransient<IUnitOfWork, UnitOfWork>();
services.AddTransient<IUnitOfWorkSecondary , UnitOfWorkSecondary>();
Le mie domande
- Qual è il design migliore (o più pratico) per questo
- Cosa succede se i database sono più di 2?