I am trying to implement UOW with repository pattern in my application.
While the independent repository is in place, but while multiple repositories in one transaction (UOW) is driving me crazy.
EF Relation One Customer - Many CustomerContacts
IUnitOfWork
public interface IUnitOfWork
: IDisposable
{
void InitTransaction();
void Rollback();
void CommitTransaction();
}
BaseUOW
public class UnitOfWork :
IUnitOfWork
{
protected DbContextTransaction _transaction;
#region IUnitOfWork
public void CommitTransaction()
{
_transaction.UnderlyingTransaction.Commit();
}
public void Rollback()
{
_transaction.UnderlyingTransaction.Rollback();
}
#endregion IUnitOfWork
}
CustomerUOW
public class CustomerUOW
: UnitOfWork
{
private IRepository<CustomerRepository> _customerRepository;
private IRepository<CustomerContactRepository> _customerContactRepository;
public BranchUOW(IRepository<CustomerRepository> customerRepository,
IRepository<CustomerContactRepository> customerContactRepository)
{
_customerRepository= customerRepository;
_customerContactRepository= customerContactRepository;
}
public override void InitTransaction()
{
_transaction.Commit();
}
}
How do I implement my
CustomerUOW
so thatCustomer
&CustomerContact
repository share the same DbContext & goes in one transaction??
Note: Each repository has an implementation of CRUD in their separate class. like
public class EntityRepository<C, T>
: BaseRepository<FoodieTenantContext, T>
where T : class
where C : CustomerContext
{
private DbSet<T> _dataSet
{
get
{
return _ctx.Set<T>();
}
}
public EntityRepository(FoodieTenantContext ctx)
: base(ctx)
{
}
public override void Add(T entity)
{
_dataSet.Add(entity);
}
public override void Delete(T entity)
{
throw new NotImplementedException();
}
public override IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
{
return _dataSet.Where(predicate).ToList<T>();
}
public override IEnumerable<T> GetAll()
{
return _dataSet.ToList<T>();
}
public override IQueryable<T> GetQuery()
{
return _dataSet;
}
public override int Save()
{
return _ctx.SaveChanges();
}
public override T Single(Expression<Func<T, bool>> predicate)
{
return _dataSet.Where(predicate).SingleOrDefault();
}
public override void Update(T entity)
{
_dataSet.Attach(entity);
_ctx.Entry<T>(entity).State = EntityState.Modified;
}
}
Thanks
On way would be to provide a Func<FoodieTenantContext, IRepository<CustomerContactRepository>>
in your CustomerUow
public abstract class UnitOfWork : IUnitOfWork
{
public UnitOfWork(FoodieTenantContext context)
{
this.Context = context;
}
// ... rest of the class
}
// usage could be like the following
public class CustomerUOW : UnitOfWork
{
public CustomerService(Func<FoodieTenantContext, IRepository<CustomerRepository>> customerRepo
, Func<FoodieTenantContext, IRepository<CustomerContactRepository>> contactRepo
, FoodieTenantContext context)
: (context)
{
_customerRepo = customerRepo(context);
_contactRepo = contactRepo(context);
}
}
Another option would be to create a RepositoryFactory, but this would mean you would have to expose a Context
property from IRepository<T>
public class RepositoryFactory
{
IServiceProvider _ioc; // This would be your IoC/DI Container
public RepositoryFactory(IServiceProvider ioc)
{
_ioc = ioc;
}
// Resolve T passing in the provided `FoodieTenantContext` into the constructor
public IRepository<T> CreateRepository<T>(FoodieTenantContext context) =>
_ioc.Resolve<T>(context);
}
Another solution could be (my least favourite) would be to expose methods in a RepositoryFactory
for each type of IRepository<T>
public class RepositoryFactory
{
public IRepository CreateCustomerContactRepository(FoodieTenantContext context) =>
return new CustomerContactRepository(context);
}
As per comment, to register Func<T>
in Castle.Windsor you can try something like the following which is a modified version of Anton's answer to Func injecting with Windsor container question. . (I am not able to test this right now)
Container.Register(
Component.For<Func<FoodieTenantContext, IRepository<CustomerRepository>>>()
.Instance((FoodieTenantContext context) => Container.Resolve<IRepository<CustomerRepository>>(new {context = context}))
)
Otherwise you could try playing around with AsFactory()
. For more info read Windsor documentation
And as a last resort, you can always fallback to manually creating a factory or switching IoC/DI containers that support Func<[TIn1, TIn2, ...], T>
out of the box, or at least natively.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.