Inject different DbContexts into generic repository based on Domain class - Autofac - c#

In my application, I need to interact with two databases. I have two domain classes which are located in two different databases. I also have a generic repository pattern which accepts an UoW in its constructor. I am looking a way to inject appropriate UoW based on Domain class. I do not want to write second generic repository for the second database.. Is there any neat solution?
public interface IEntity
{
int Id { get; set; }
}
Located in Database A
public class Team: IEntity
{
public int Id { get; set; }
public string Name{ get; set; }
}
Located in Database B
public class Player: IEntity
{
public int Id { get; set; }
public string FullName { get; set; }
}
I also have a generic repository pattern with UoW
public interface IUnitOfWork
{
IList<IEntity> Set<T>();
void SaveChanges();
}
public class DbADbContext : IUnitOfWork
{
public IList<IEntity> Set<T>()
{
return new IEntity[] { new User() { Id = 10, FullName = "Eric Cantona" } };
}
public void SaveChanges()
{
}
}
public class DbBDataContext: IUnitOfWork
{
public IList<IEntity> Set<T>()
{
return new IEntity[] { new Tender() { Id = 1, Title = "Manchester United" } };
}
public void SaveChanges()
{
}
public interface IRepository<TEntity> where TEntity: class, IEntity
{
IList<IEntity> Table();
}
public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class, IEntity
{
protected readonly IUnitOfWork Context;
public BaseRepository(IUnitOfWork context)
{
Context = context;
}
IList<IEntity> IRepository<TEntity>.Table()
{
return Context.Set<TEntity>();
}
}
I've already found articles saying that Autofac overrides the registration with the last value. I know my problem is how DbContexts are registered.
var builder = new ContainerBuilder();
// problem is here
builder.RegisterType<DbADbContext >().As<IUnitOfWork>()
builder.RegisterType<DbBDbContext >().As<IUnitOfWork>()
builder.RegisterGeneric(typeof(BaseRepository<>)).As(typeof(IRepository<>));
var container = builder.Build();

I inspired from #tdragon's answer.
The first step is registering Named DbContext
builder.RegisterType<Database1>()
.Keyed<IUnitOfWork>(DbName.Db1)
.Keyed<DbContext>(DbName.Db1).AsSelf().InstancePerRequest();
builder.RegisterType<Database2>()
.Keyed<IUnitOfWork>(DbName.Db2)
.Keyed<DbContext>(DbName.Db2).AsSelf().InstancePerRequest();
Please note that DbName is just an enum.
The following code scans the data access layer assembly for finding Domain classes. Then, it registers ReadOnlyRepository and BaseRepository. the place of this code is in DIConfig
Type entityType = typeof(IEntity);
var entityTypes = Assembly.GetAssembly(typeof(IEntity))
.DefinedTypes.Where(t => t.ImplementedInterfaces.Contains(entityType));
var baseRepoType = typeof(BaseRepository<>);
var readOnlyRepoType = typeof(ReadOnlyRepository<>);
var baseRepoInterfaceType = typeof(IRepository<>);
var readOnlyRepoInterfaceType = typeof(IReadOnlyRepository<>);
var dbContextResolver = typeof(DbContextResolverHelper).GetMethod("ResolveDbContext");
foreach (var domainType in entityTypes)
{
var baseRepositoryMaker = baseRepoType.MakeGenericType(domainType);
var readonlyRepositoryMarker = readOnlyRepoType.MakeGenericType(domainType);
var registerAsForBaseRepositoryTypes = baseRepoInterfaceType.MakeGenericType(domainType);
var registerAsForReadOnlyRepositoryTypes = readOnlyRepoInterfaceType.MakeGenericType(domainType);
var dbResolver = dbContextResolver.MakeGenericMethod(domainType);
// register BaseRepository
builder.Register(c => Activator.CreateInstance(baseRepositoryMaker, dbResolver.Invoke(null, new object[] { c }))
).As(registerAsForBaseRepositoryTypes).InstancePerRequest(jobTag);
//register readonly repositories
builder.Register(c => Activator.CreateInstance(readonlyRepositoryMarker, dbResolver.Invoke(null, new object[] { c })))
.As(registerAsForReadOnlyRepositoryTypes).InstancePerRequest(jobTag);
}
The following methods try to find DbSet in each DbContext in order to find out the Domain Classes belongs to which DataContext/Database.
public class DbContextResolverHelper
{
private static readonly ConcurrentDictionary<Type, DbName> TypeDictionary = new ConcurrentDictionary<Type, DbName>();
public static DbContext ResolveDbContext<TEntity>(IComponentContext c) where TEntity : class, IEntity
{
var type = typeof(DbSet<TEntity>);
var dbName = TypeDictionary.GetOrAdd(type, t =>
{
var typeOfDatabase1 = typeof(Database1);
var entityInDatabase1 = typeOfDatabase1 .GetProperties().FirstOrDefault(p => p.PropertyType == type);
return entityInDatabase1 != null ? DbName.Db1: DbName.Db2;
});
return c.ResolveKeyed<DbContext>(dbName);
}
}

What about this:
builder.RegisterType<DbContextBase>().As<IUnitOfWork>()
And
DbADataContext: DbContextBase,IUnitOfWork
DbBDataContext: DbContextBase,IUnitOfWork
Or in your registration you can just do something like :
containerBuilder.RegisterGeneric(typeof(DbADataContext<>)).Named("DbADataContext", typeof(IUnitOfWork<>));
containerBuilder.RegisterGeneric(typeof(DbBDataContext<>)).Named("DbBDataContext", typeof(IUnitOfWork<>));

If you want to keep single BaseRepository and its interface, you have to somehow configure, with entity would be handled by which DbContext. It could be done in registration part of application, but in that case you cannot register your BaseRepostory<T> as open generic, but be explicit in your registrations, like this:
containerBuilder.RegisterType<DbADataContext>().Named<IUnitOfWork>("A");
containerBuilder.RegisterType<DbBDataContext>().Named<IUnitOfWork>("B");
containerBuilder.Register(c => new BaseRepository<Team>(c.ResolveNamed<IUnitOfWork>("A")).As<IRepostory<Team>>();
containerBuilder.Register(c => new BaseRepository<Player>(c.ResolveNamed<IUnitOfWork>("B")).As<IRepository<Player>>();
(just proof of concept, code not tested)
Autofac is not smart enough to know "automatically" which unit of work you want to use in each of your repository.

Related

Implement different concretions to an abstract class that implements a generic service [duplicate]

This question already has an answer here:
Register partically closed generic type with Autofac
(1 answer)
Closed 3 years ago.
I have a generic interface and one generic class with generic methods to query the database.
public interface IRepositoryBase<Entity> {
IEnumerable<TEntity> GetAll(Func<IQueryable<TEntity>, IncludableQueryable<TEntity, object>> include = null);
}
public class RepositoryBase<TEntity>
: IDisposable, IRepositoryBase<TEntity>
where TEntity : class
{
public IEnumerable<TEntity> GetAll(Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>> include = null)
{
IQueryable<TEntity> query = _context.Set<TEntity>();
if (include != null)
query = include(query);
return query.ToList();
}
}
I also have several classes that I call "services" that have the business logic and implement another generic interface.
public interface IServiceBase<TEntity>
where TEntity : class
{
IEnumerable<TEntity> GetAll(Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>> include = null);
}
public class ServiceBase<TEntity>
: IDisposable, IServiceBase<TEntity>
where TEntity : class
{
private readonly IRepositoryBase<TEntity>
_repository;
public ServiceBase(
IRepositoryBase<TEntity> repository)
{
_repository = repository;
}
public ServiceBase()
{
}
public IEnumerable<TEntity> GetAll(Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>> include = null)
{
return _repository.GetAll(include);
}
}
public class PizzaService : ServiceBase<Piza>, IPizzaService
{
private readonly IPizzaRepository _pizzaRepository;
public PizzaService (IPizzaRepository pizzaRepository)
: base(pizzaRepository)
{
_pizzaRepository= pizzaRepository;
}
}
This way each service have their methods acessing their own table plus the methods in the ServiceBase.
There is a scenario where I have 3 concrete services like PizzaService, each one querying its own table, with really similar code, because of the table and the logic similarity.
I want to refactor those concrete services into one, changing only the method param and the repository being acessed, to be in compliance to DRY and ISP.
What I currently have:
public interface IStopRule
{
string DsTerm { get; set; }
bool ShouldDelete { get; set; }
}
public interface IExampleRuleStopWordsBase<TEntity> : IServiceBase<TEntity>
where TEntity : class
{
}
public abstract class ExampleRuleStopWordsBase
: ServiceBase<IStopRule>, IExampleRuleStopWordsBase<IStopRule>
{
private readonly IRepositoryBase<IStopRule> _repo;
public ExampleRuleStopWordsBase(IRepositoryBase<IStopRule> repo)
: base()
{
_repo = repo;
}
public virtual string ApplyRule(string input)
{
var terms = GetAll();
foreach (var item in terms)
{
string regexPattern = #"\b(" + item.DsTerm + #")\b";
if (item.ShouldDelete && Regex.Match(input, regexPattern, RegexOptions.IgnoreCase).Success)
input = input.Replace(item.DsTerm, string.Empty);
}
input = input.Trim();
return input;
}
}
public class PizzaService : ExampleRuleStopWordsBase, IImportRule
{
public PizzaService(IRepositoryBase<IStopRule> repo)
: base(repo)
{
}
public void ApplyRule(Pizza pizza)
{
base.ApplyRule(pizza.Name);
}
}
public class PizzaProducerService : ExampleRuleStopWordsBase, IImportRule
{
public PizzaProducerService(IRepositoryBase<IStopRule> repo)
: base(repo)
{
}
public void ApplyRule(Pizza pizza)
{
base.ApplyRule(pizza.Producer.Name);
}
}
But I can't figure it out how to pass to the consturctor of ImportRuleStopWordsBase the right entity to make it use the right repository...
Obs: All interfaces and service implementations reside in Domain layers, whereas the implementation of the repository resides in Infrastructure layer.
It looks like you're looking for .RegisterGeneric here if I understand correctly. The example for your classes might be:
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<PizzaService>();
containerBuilder.RegisterType<PizzaProducerService>();
containerBuilder.RegisterGeneric(typeof(RepositoryBase<>))
.As(typeof(IRepositoryBase<>));
var container = containerBuilder.Build();
using (var scope = container.BeginLifetimeScope())
{
var pizzaService = scope.Resolve<PizzaService>();
var pizzaProducerService = scope.Resolve<PizzaProducerService>();
}

Moq - Update with DbEntityEntry

I'm using EF6. The generated code is something like:
public partial class MyDataContext : DbContext
{
public MyDataContext() : base("name=mydata")
{
}
public virtual DbSet<Book> Books { get; set; }
}
Then I have a generic repository like:
public class GenericRepository<TObject> where TObject : class
{
protected readonly MyDataContext Context;
protected GenericRepository(MyDataContext context)
{
Context = context;
}
public virtual TObject Update(TObject data, int id)
{
if (data == null)
return null;
TObject obj = Context.Set<TObject>().Find(id);
if (obj != null)
{
Context.Entry(obj).CurrentValues.SetValues(data);
Context.SaveChanges();
}
return obj;
}
}
Then I have a service that uses the GenericRepository to update data:
public class MyDataService<TObject> where TObject : class
{
private readonly MyDataContext context;
public MyDataService(MyDataContext ct)
{
context = ct;
}
public TObject Update(TObject obj, int id)
{
var r = new GenericRepository<TObject>(context);
return r.Update(obj, id);
}
}
So I can update a books with something like this:
var ds = new MyDataService<Book>(new MyDataContext());
var data = ds.Update(new Book { Name = "New Name" }, 1);
This is working fine. Next I try to use Moq to unit test the above code with something like:
var updatedBook = new Book { Name = "Update Book Name" };
var mockSet = new Mock<DbSet<Book>>();
var mockContext = new Mock<MyDataContext>();
mockContext.Setup(c => c.Books).Returns(mockSet.Object);
mockContext.Setup(c => c.Set<Book>().Find(It.IsAny<object[]>()))
.Returns<object[]>(ids => chips.FirstOrDefault(d => d.Id == (int)ids[0]));
var service = new MyDataService<Book>(mockContext.Object);
var data = service.Update(updatedBook, 1);
However, I get an exception on the Context.Entry(obj).CurrentValues.SetValues(data) line.
How do I mock the Update method properly?
You could implement an interface for MyDataService to be able to mock it
public Interface IMyDataService<TObject> where TObject : class
{
TObject Update(TObject obj, int id);
}
public class MyDataService<TObject>:IMyDataService<TObject>
where TObject : class
{
private readonly MyDataContext context;
public MyDataService(MyDataContext ct)
{
context = ct;
}
public TObject Update(TObject obj, int id)
{
var r = new GenericRepository<TObject>(context);
return r.Update(obj, id);
}
}
Moq:
var mockDataService = new Mock<IMyDataService<Book>>();
mockDataService.Setup(c=> c.Update(It.Any<Book>(),It.Any<int>()).Returns(updatedbook);
The service should be dependent on the repository. Passing the context directly to the service is misleading as what the service really needs and uses is the repository.
Your classes should depend on abstractions and not on concretions. That said, all the above classes could be abstracted behind interfaces. but for now I'll focus on the service class and it's dependence on the repository. You are coupling different layers too closely. Service layer doesn't need to know about data context
Abstract the repository to allow for easier testability
interface IGenericRepository<TObject> where TObject : class {
TObject Update(TObject data, int id);
}
public class GenericRepository<TObject> : IGenericRepository<TObject> where TObject : class {
protected readonly MyDataContext Context;
public GenericRepository(MyDataContext context) {
Context = context;
}
public virtual TObject Update(TObject data, int id) {
if (data == null)
return null;
TObject obj = Context.Set<TObject>().Find(id);
if (obj != null) {
Context.Entry(obj).CurrentValues.SetValues(data);
Context.SaveChanges();
}
return obj;
}
}
The service would only now need to know about the repository abstraction, not its implementation details.
public class MyDataService<TObject> where TObject : class {
private readonly IGenericRepository<TObject> repository;
public MyDataService(IGenericRepository<TObject> repository) {
this.repository = repository;
}
public TObject Update(TObject obj, int id) {
return repository.Update(obj, id);
}
}
So now the service can be tested in isolation without any need to worry about any data context
//Arrange
var updatedBook = new Book { Name = "Update Book Name" };
var id = 1;
var mockRepository = new Mock<IGenericRepository<Book>>();
mockRepository
.Setup(m => m.Update(updatedBook, id))
.Returns(updatedBook);
var service = new MyDataService<Book>(mockRepository.Object);
//Act
var data = service.Update(updatedBook, id);
//Assert
//...
When it's time to unit test the repository implementation in isolation, then you can follow the same structure and abstract the context for the repository implementation.
I would suggest the small refactoring in order to make the testing easier and even possible. With this implementation you are relying on the implementation of the DbContext and DbEntityEntry.
At first extract interface for your context:
public inteface IMyDataContext<TObject> where TObject is class
{
TObject FindById(int id); //call FindId
void Update(TObject); //call DbEntityEntry SetValues
void SaveChanges();
}
In the GenericRepository then inject the interface. This will make your life easier, you can then easily mock all method. Unit tests of the repository should verify that right methods of the context are called.

Fluent Nhibernate : How to make Search Class Generic in best possible way

I have a class say 'AllInvoices', the structure of which is as below :
public class ActiveInvoices
{
public string InvoiceId { get; set; }
public string InvoiceIssueDate { get; set; }
public string InvoiceTransactionDate { get; set; }
public string InvoiceExpiryDate { get; set; }
}
The mapping class for Entity ActiveInvoices is
public class ActiveInvoicesMap : ClassMap<ActiveInvoices>
{
public ActiveInvoicesMap()
{
Id(x => x.InvoiceId);
Map(x => x.InvoiceIssueDate);
Map(x => x.InvoiceTransactionDate);
Map(x => x.InvoiceExpiryDate);
}
}
Now with this entity I search for Active Invoices in database with the following class
public class SearchInvoices
{
public readonly IRepository<ActiveInvoices> latestActiveInvoicesRepository;
public SearchInvoices(IRepository<ActiveInvoices> activeInvoicesRepository)
{
latestActiveInvoicesRepository = activeInvoicesRepository;
}
public List<ActiveInvoices> GetActiveInvoices()
{
var listOfActiveInvoices = latestActiveInvoicesRepository.GetAll();
return listOfActiveInvoices;
}
}
To Search Active Invoices I call the Search Class method 'GetActiveInvoices()' from a workflow class which looks like below :
public class CurrentWorkFlow
{
public void GetActiveInvoices()
{
var invoiceSearch = new SearchInvoices(IRepository <ActiveInvoices> repository);
}
}
Now the issue in hand is that I need to make class 'SearchInvoices' generic to support all other possible types that i would create like 'ExpiredInvoices', 'ArchivedInvoices', 'FutureInvoices' etc and not just only for type 'ActiveInvoices'.
These new types may or may not have the same structure as 'ActiveInvoices'.
I have tried to use dynamic but thought of asking experts around here if they have any better ideas to implement the required functionality
in most optimized generic manner.
Regrets for being very detailed and lengthy in asking but i thought to include as many details as i can. Hope it goes well with you folks.
Couldn't you make a generic repository like this? -
interface IDomain{
}
class ExpiredInvoices: IDomain{
}
class ActiveInvoices: IDomain{
}
interface IRepository{
}
class Repsoitory: IRepository {
public static IList<T> Get<T>() where T: IDomain //default one
{
using (ISession session = OpenEngineSession())
{
return session.Query<T>().ToList();
}
}
public static IList<T> Get<T>(Expression<Func<T, bool>> expression) where T: IDomain // overloaded get with linq predicate
{
using (ISession session = OpenEngineSession())
{
return session.Query<T>().Where(expression).ToList();
}
}
}
Then use it like -
var repo = // get IRepository
var activeInvoices = repo.Get<ActiveInvoices>();
var expiredInvoices = repo.Get<ExpiredInvoices>();
EDIT: As Repository cannot be changed, suggested by OP
If you cannot change the repository, then I would suggest making the search service interface dependent, rather than concrete class -
interface IInvoice{
}
class ExpiredInvoices: IInvoice{
}
class ActiveInvoices: IInvoice{
}
public class SearchInvoices
{
public readonly IRepository<IInvoice> latestActiveInvoicesRepository;
public SearchInvoices(IRepository<IInvoice> activeInvoicesRepository)
{
latestInvoicesRepository = activeInvoicesRepository;
}
public List<T> GetActiveInvoices<T>() where T: IInvoice
{
var listOfActiveInvoices = latestActiveInvoicesRepository.GetAll();
return listOfActiveInvoices;
}
}
Then call like -
var ss = new SearchService(IRepository <ActiveInvoices> repository);
var items = ss.GetActiveInvoices<ActiveInvoices>();
Or,
public class SearchInvoices<T> where T: IInvoice
{
public readonly IRepository<T> latestActiveInvoicesRepository;
public SearchInvoices(IRepository<T> activeInvoicesRepository)
{
latestInvoicesRepository = activeInvoicesRepository;
}
public List<T> GetActiveInvoices()
{
var listOfActiveInvoices = latestActiveInvoicesRepository.GetAll();
return listOfActiveInvoices;
}
}
then call like -
var ss = new SearchService<ActiveInvoices>(IRepository <ActiveInvoices> repository);
var items = ss.GetActiveInvoices();
Whichever suits you.

Registering different UnitOfWorks per each module for a generic CommandHandler using structuremap

I'm using CQRS pattern in my recent project, and used EF code first in my DAL, so I defined some generic CommandHandlers to do Insert/Update/Delete:
public class InsertCommandHandler<TEntity> : ICommandHandler<InsertCommandParameter<TEntity>>
where TEntity : BaseEntity, IAggregateRoot<TEntity>, new()
{
private readonly IUnitOfWork _uow;
public InsertCommandHandler(IUnitOfWork uow)
{
_uow = uow;
}
public void Handle(InsertCommandParameter<TEntity> parameter)
{
var entity = parameter.Entity;
_uow.Repository<TEntity>().Add(entity);
}
}
public interface ICommandParameter
{
}
public abstract class BaseEntityCommandParameter<T> : ICommandParameter
where T : BaseEntity, new()
{
public T Entity { get; set; }
protected BaseEntityCommandParameter()
{
Entity = new T();
}
}
public class InsertCommandParameter<T> : BaseEntityCommandParameter<T> where T : class, new()
{
}
As you see I injected the IUnitOfWork to the InsertCommandHandler constructor.
public interface IUnitOfWork : IDisposable
{
IRepository<T> Repository<T>() where T : BaseEntity, IAggregateRoot<T>,new ();
void Commit();
}
I used Structuremap 3 as my IoC Container, So I defined following conversion to resolve ICommandHandlers for each BaseEntity types(using custom registration conventions for partially closed types):
public class CRUDCommandRegistrationConvention : StructureMap.Graph.IRegistrationConvention
{
private static readonly
Type _openHandlerInterfaceType = typeof(ICommandHandler<>);
private static readonly
Type _openInsertCommandType = typeof(InsertCommandParameter<>);
private static readonly
Type _openInsertCommandHandlerType = typeof(InsertCommandHandler<>);
private static readonly
Type _openUpdateCommandType = typeof(UpdateCommandParameter<>);
private static readonly
Type _openUpdateCommandHandlerType = typeof(UpdateCommandHandler<>);
private static readonly
Type _openDeleteCommandType = typeof(DeleteCommandParameter<>);
private static readonly
Type _openDeleteCommandHandlerType = typeof(DeleteCommandHandler<>);
public void Process(Type type, Registry registry)
{
if (!type.IsAbstract && typeof(BaseEntity).IsAssignableFrom(type))
if (type.GetInterfaces()
.Any(x => x.IsGenericType && x.GetGenericTypeDefinition()
== typeof(IAggregateRoot<>)))
{
Type closedInsertCommandType = _openInsertCommandType.MakeGenericType(type);
Type closedInsertCommandHandlerType = _openInsertCommandHandlerType.MakeGenericType(type);
Type closedUpdateCommandType = _openUpdateCommandType.MakeGenericType(type);
Type closedUpdateCommandHandlerType = _openUpdateCommandHandlerType.MakeGenericType(type);
Type closedDeleteCommandType = _openDeleteCommandType.MakeGenericType(type);
Type closedDeleteCommandHandlerType = _openDeleteCommandHandlerType.MakeGenericType(type);
Type insertclosedHandlerInterfaceType = _openHandlerInterfaceType.MakeGenericType(closedInsertCommandType);
Type updateclosedHandlerInterfaceType = _openHandlerInterfaceType.MakeGenericType(closedUpdateCommandType);
Type deleteclosedHandlerInterfaceType = _openHandlerInterfaceType.MakeGenericType(closedDeleteCommandType);
registry.For(insertclosedHandlerInterfaceType).Use(closedInsertCommandHandlerType);
registry.For(updateclosedHandlerInterfaceType).Use(closedUpdateCommandHandlerType);
registry.For(deleteclosedHandlerInterfaceType).Use(closedDeleteCommandHandlerType);
}
}
}
And used it in my CompositionRoot:
public static class ApplicationConfiguration
{
public static IContainer Initialize()
{
ObjectFactory.Initialize(x =>
{
x.Scan(s =>
{
s.AssemblyContainingType(typeof(ICommandHandler<>));
s.AssemblyContainingType(typeof(Order));
s.AssemblyContainingType(typeof(FindOrderByIdQueryHandler));
s.WithDefaultConventions();
x.For(typeof(IUnitOfWork))
.Use(typeof(EfUnitOfWork<SaleDBContext>))
.Named("SaleDBContext")
.SetLifecycleTo((Lifecycles.Singleton));
s.Convention<CRUDCommandRegistrationConvention>();
});
});
return ObjectFactory.Container;
}
public static T Resolve<T>()
{
return ObjectFactory.GetInstance<T>();
}
}
I registered EfUnitOfWork<SaleDBContext> for IUnitOfWork, but I want to use separate DbContext per each module in my solution(Bounded context). For example my sale module has its own DbContext, HR module has its own DbContext and etc, and above registration conversion, only register EfUnitOfWork<SaleDBContext> as my IUnitOfWork.
I have some modules(Solution Folders in Visual Studio) in my solution and each module has 3 layer(3 class library projects):
My modules has following structure(each module has 3 assemblies) for example:
SaleModule:
----Application
----Domain (Entities , ...) //Order, Customer,...
----DAL (DbContext ,...) //SaleDbContext
HRModule:
----Application
----Domain (Entities , ...) // Employee, OrganizationUnit, ...
----DAL (DbContext ,...)//HRDbContext
InfrastructureModule:
----Application (ICommandHandler,IQueryHandler,...)
----Domain
----DAL
The InsertCommandHandler<T> puts in Infrastructure Module.
When I use the InsertCommanHandler<T> I want it uses corresponding module's DbContext as IUnitOfWork. for example, I want the InsertCommandHandler<Order> uses SaleDbContext as it's IUnitOfWork and InsertCommandHandler<Employee> uses HRDbContext as it's IUnitOfWork.
[UPDATED]
This is a sample of cunsumers code that IoC containar should provide SaleDbContext for Consumer1 and HRDbContext for Consumer2:
public class Consumer1
{
ICommandHandler<InsertCommandParameter<Order>> _insertCommandHandler;
public Consumer1(ICommandHandler<InsertCommandParameter<Order>> insertCommandHandler)
{
_insertCommandHandler = insertCommandHandler;
}
public void DoInsert()
{
var command = new InsertCommandParameter<Order>();
command.Entity = new Order(){
Number = 'ord-01',
// other properties
};
insertCommandHandler.Handle(command); //this query handler should use SaleDbContext
}
}
public class Consumer2
{
ICommandHandler<InsertCommandParameter<Employee>> _insertCommandHandler;
public Consumer2(ICommandHandler<InsertCommandParameter<Employee>> insertCommandHandler)
{
_insertCommandHandler = insertCommandHandler;
}
public void DoInsert()
{
var command = new InsertCommandParameter<Employee>();
command.Entity = new Employee(){
EmployeeNumber = 'Emp1',
// other properties
};
insertCommandHandler.Handle(command); //this query handler should use HRDbContext
}
}
How could I do that in my composition root using StructureMap?
You can make IUnitOfWork generic as in IUnitOfWork<TConnection>. This allows each Repository to stipulate which UnitOfWork it requires, ideally using constructor injection, e.g.
public class InsertCommandHandler : ICommandHandler<Order>
{
public InsertCommandHandler(IUnitOfWork<SalesDbContext> salesUnitOfWork)
{
// ...
}
}
However, you probably don't want to reference the DbContext in each handler so you should define an abstraction to avoid such a dependency.
Start with a simple interface that all DbContext wrapper classes will implement
public interface IConnection
{
DbContext Context { get; }
}
Update IUnitOfWork accordingly
public interface IUnitOfWork<TConnection> where TConnection : IConnection { }
Here's an example wrapper
public class SalesConnection : IConnection
{
private readonly DbContext context;
public SalesConnection()
{
this.context = new SalesDbContext();
}
public DbContext Context { get { return this.context; } }
}
And here's what the updated command handler will look like
public class InsertCommandHandler : ICommandHandler<Order>
{
public InsertCommandHandler(IUnitOfWork<SalesConnection> salesUnitOfWork)
{
// ...
}
}
UPDATE
The logical thing to do for common handlers is to have one per logical domain (i.e. per DbContext), for example SalesInsertCommandHandler, HRInsertCommandHandler
public class SalesInsertCommandHandler<TCommand> : ICommandHandler<TCommand>
{
public SalesInsertCommandHandler(IUnitOfWork<SalesConnection> unitOfWork)
{
}
}
This adheres to the separation of concerns principle and gives you extra flexibility when you come to decorate your concerns with different aspects (tracing, retry logic etc.)
All command handlers can of course inherit from a single common (abstract) command handler.
public abstract class CommandHandler<TConnection, TCommand> :
ICommandHandler<TCommand>
where TConnection : IConnection
{
private readonly IUnitOfWork<TConnection> unitOfWork;
public CommandHandler(IUnitOfWork<TConnection> unitOfWork)
{
this.unitOfWork = unitOfWork;
}
}
public class SalesInsertCommandHandler<TCommand> :
CommandHandler<SalesConnection, TCommand>
{
}

Linq2SQL+Repository pattern: how to implement type related mapping

I have the Repository pattern implemented to access DB data through the Linq2Sql ORM:
public abstract class RepositoryBase<T, TDb> : IRepository<T>
where T : IEntity
where TDb : class, IDbEntity, new()
{
protected RepositoryBase(IUnityContainer container)
{
_container = container;
_context = _container.Resolve<CMCoreDataClassesDataContext>();
}
public IQueryable<T> GetAll()
{
return GetTable().Select(GetConverter());
}
protected abstract Table<TDb> GetTable();
protected abstract Expression<Func<TDb, T>> GetConverter();
protected CMCoreDataClassesDataContext Context { get { return _context; } }
private readonly IUnityContainer _container;
private readonly CMCoreDataClassesDataContext _context;
}
Here is an example of particular Repository implementation:
public class CustomerProductRepository
: RepositoryBase<ICommonCustomerProduct, CMCoreDAL.DbData.CustomerProduct>
{
protected override Table<CMCoreDAL.DbData.CustomerProduct> GetTable()
{
return Context.CustomerProducts;
}
protected override Expression<Func<CMCoreDAL.DbData.CustomerProduct, ICommonCustomerProduct>> GetConverter()
{
return dbEntity => dbEntity.ProdId == (int)ProductType.ProductTypeEnum.CommonProduct
? new CommonCustomerProduct
{
UnityContainer = UnityContainer,
InstanceId = dbEntity.InstanceId,
CustomerId = dbEntity.CustomerID,
StatusCode = dbEntity.StatusCode,
DeviceLicenses = dbEntity.DeviceLicenses,
ServerLicenses = dbEntity.ServerLicenses,
}
: new SpecificCustomerProduct()
{
UnityContainer = UnityContainer,
InstanceId = dbEntity.InstanceId,
CustomerId = dbEntity.CustomerID,
StatusCode = dbEntity.StatusCode,
UserLicenses = dbEntity.DeviceLicenses,
}
;
}
Here SpecificCustomerProduct is inherited from CommonCustomerProduct.
Presented source code shows how records from DB are mapped to different instances according to instance type. There are a lot of common fields for these classes and only few of them are different.
I have 2 concerns for this code:
Some duplications of assignment operations;
Low readability: in order to add few more concrete classes I need to make unreadable chain:
return dbEntity => dbEntity.ProdId == iType1
? new Type1
{
... assignments
}
:
{
dbEntity.ProdId == iType2
? new Type2
{
... assignments
}
: new Type3
{
... assignments
}
}
Is there any better way to implement 'type-related' mapping with such pattern?
Have you looked at LINQ to SQL's Inheritance mapping? It allows you to map different classes to a common table, using a database column (type discriminator) to determine which type of object to generate.

Categories

Resources