using System.Data.Entity;
using System.Threading.Tasks;
using Microsoft.Practices.Unity;
using System.Linq.Expressions;
public static void Main()
var container = new UnityContainer();
InitializeContainer(container);
var childContainer = container.CreateChildContainer();
var designTimeService = childContainer.Resolve<MyDesignTimeMasterService>();
designTimeService.DoStuff();
childContainer.Dispose();
childContainer = container.CreateChildContainer();
var runTimeService = childContainer.Resolve<MyRunTimeGroupService>();
runTimeService.DoStuff(Group2DataContextToken.Token);
childContainer.Dispose();
public static IUnityContainer InitializeContainer(IUnityContainer container)
container.RegisterType<IDataContext<MasterDataContextToken>, DataContext<MasterDataContextToken>>(new InjectionConstructor("name=MasterDB", MasterDataContextToken.Token));
container.RegisterType<IDataContext<Group1DataContextToken>, DataContext<Group1DataContextToken>>(new InjectionConstructor("name=Group1", Group1DataContextToken.Token));
container.RegisterType<IDataContext<Group2DataContextToken>, DataContext<Group2DataContextToken>>(new InjectionConstructor("name=Group2", Group2DataContextToken.Token));
container.RegisterType<IDataContext<Group3DataContextToken>, DataContext<Group3DataContextToken>>(new InjectionConstructor("name=Group3", Group3DataContextToken.Token));
container.RegisterType(typeof(IRepository<,>), typeof(Repository<,>));
container.RegisterType(typeof(IUnitOfWork<>), typeof(UnitOfWork<>), new HierarchicalLifetimeManager());
container.RegisterType<IDataContext>(MasterDataContextToken.Token, new InjectionFactory(c => c.Resolve<IDataContext<MasterDataContextToken>>()));
container.RegisterType<IDataContext>(Group1DataContextToken.Token, new InjectionFactory(c => c.Resolve<IDataContext<Group1DataContextToken>>()));
container.RegisterType<IDataContext>(Group2DataContextToken.Token, new InjectionFactory(c => c.Resolve<IDataContext<Group2DataContextToken>>()));
container.RegisterType<IDataContext>(Group3DataContextToken.Token, new InjectionFactory(c => c.Resolve<IDataContext<Group3DataContextToken>>()));
container.RegisterType<IUnitOfWork>(MasterDataContextToken.Token, new InjectionFactory(c => c.Resolve<IUnitOfWork<MasterDataContextToken>>()));
container.RegisterType<IUnitOfWork>(Group1DataContextToken.Token, new InjectionFactory(c => c.Resolve<IUnitOfWork<Group1DataContextToken>>()));
container.RegisterType<IUnitOfWork>(Group2DataContextToken.Token, new InjectionFactory(c => c.Resolve<IUnitOfWork<Group2DataContextToken>>()));
container.RegisterType<IUnitOfWork>(Group3DataContextToken.Token, new InjectionFactory(c => c.Resolve<IUnitOfWork<Group3DataContextToken>>()));
container.RegisterType(typeof(IRepository<>), MasterDataContextToken.Token, new InjectionFactory((c, t, n) => ResolveRepository<MasterDataContextToken>(c, t)));
container.RegisterType(typeof(IRepository<>), Group1DataContextToken.Token, new InjectionFactory((c, t, n) => ResolveRepository<Group1DataContextToken>(c, t)));
container.RegisterType(typeof(IRepository<>), Group2DataContextToken.Token, new InjectionFactory((c, t, n) => ResolveRepository<Group2DataContextToken>(c, t)));
container.RegisterType(typeof(IRepository<>), Group3DataContextToken.Token, new InjectionFactory((c, t, n) => ResolveRepository<Group3DataContextToken>(c, t)));
container.RegisterType(typeof(IRepositoryManager<>), typeof(RepositoryManager<>));
container.RegisterType<IUnitOfWorkManager, UnitOfWorkManager>();
private static object ResolveRepository<TDataContextToken>(IUnityContainer container, Type repositoryType)
Type entityType = repositoryType.GetGenericArguments()[0];
Type tokenRepositoryType = typeof(IRepository<,>).MakeGenericType(typeof(TDataContextToken), entityType);
return container.Resolve(tokenRepositoryType);
public class MyDesignTimeMasterService
private readonly IUnitOfWork _masterUnitOfWork;
private readonly IRepository<MyMasterEntity> _masterEntityRepository;
public MyDesignTimeMasterService(IUnitOfWork<MasterDataContextToken> masterUnitOfWork, IRepository<MasterDataContextToken, MyMasterEntity> masterEntityRepository)
_masterUnitOfWork = masterUnitOfWork;
_masterEntityRepository = masterEntityRepository;
var foo = _masterEntityRepository.FindOne(e => e.Name == "Foo");
_masterEntityRepository.Delete(foo);
_masterUnitOfWork.SaveChanges();
public class MyRunTimeGroupService
private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly IRepositoryManager<MyGroupEntity> _groupEntityRepository;
public MyRunTimeGroupService(IUnitOfWorkManager unitOfWorkManager, IRepositoryManager<MyGroupEntity> groupEntityRepository)
_unitOfWorkManager = unitOfWorkManager;
_groupEntityRepository = groupEntityRepository;
public void DoStuff(string repositoryToken)
var unitOfWork = _unitOfWorkManager.GetUnitOfWork(repositoryToken);
var repository = _groupEntityRepository.GetRepository(repositoryToken);
var bar = repository.FindOne(e => e.Name == "Bar");
unitOfWork.SaveChanges();
public abstract class EntityBase {}
public class MyMasterEntity : EntityBase
public string Name { get; set; }
public class MyGroupEntity : EntityBase
public string Name { get; set; }
public interface IDataContext
string DataContextToken { get; }
IQueryable<T> Set<T>() where T : EntityBase;
Task SaveChangesAsync(CancellationToken cancellationToken);
public interface IDataContext<TDataContextToken> : IDataContext where TDataContextToken : IDataContextToken
public class DataContext : IDataContext
private readonly string _nameOrConnectionString;
private readonly string _dataContextToken;
public DataContext(string nameOrConnectionString, string dataContextToken)
_nameOrConnectionString = nameOrConnectionString;
_dataContextToken = dataContextToken;
public IQueryable<T> Set<T>() where T : EntityBase { return null; }
public Task SaveChangesAsync(CancellationToken cancellationToken) { return Task.FromResult(true); }
public Task SaveChangesAsync() { return Task.FromResult(true); }
Console.WriteLine("SaveChanges called on data context with connection string: " + _nameOrConnectionString);
public string DataContextToken { get { return _dataContextToken; } }
public class DataContext<TDataContextToken> : DataContext, IDataContext<TDataContextToken> where TDataContextToken : IDataContextToken
public DataContext(string nameOrConnectionString, string dataContextToken) : base(nameOrConnectionString, dataContextToken)
public interface IRepository<TEntity> where TEntity : EntityBase
string DataContextToken { get; }
IQueryable<TEntity> Set { get; }
void Add(TEntity entity);
void Delete(TEntity entity);
TEntity FindOne(Expression<Func<TEntity, bool>> predicate);
IQueryable<TEntity> FindBy(Expression<Func<TEntity, bool>> predicate);
IQueryable<TEntity> GetAll();
void Update(TEntity entity);
Task<TEntity> FindAsync( params object[] keyValues );
Task<TEntity> FindAsync( CancellationToken cancellationToken, params object[] keyValues );
Task<bool> DeleteAsync( params object[] keyValues );
Task<bool> DeleteAsync( CancellationToken cancellationToken, params object[] keyValues );
public interface IRepository<TDataContextToken, TEntity> : IRepository<TEntity> where TEntity : EntityBase where TDataContextToken : IDataContextToken
public class Repository<TEntity> : IRepository<TEntity> where TEntity : EntityBase
IDataContext _dataContext;
public Repository(IDataContext dataContext)
_dataContext = dataContext;
public string DataContextToken { get { return _dataContext.DataContextToken; } }
public IQueryable<TEntity> Set { get { return _dataContext.Set<TEntity>(); } }
public void Add(TEntity entity) {}
public void Delete(TEntity entity)
Console.WriteLine("Delete called on repository for type: " + typeof(TEntity).Name + " with context: " + DataContextToken);
public void Delete(dynamic id) {}
public TEntity FindOne(Expression<Func<TEntity, bool>> predicate)
Console.WriteLine("FindOne called on repository for type: " + typeof(TEntity).Name + " with context: " + DataContextToken);
public IQueryable<TEntity> FindBy(Expression<Func<TEntity, bool>> predicate) { return (new TEntity[0]).AsQueryable(); }
public IQueryable<TEntity> GetAll() { return (new TEntity[0]).AsQueryable(); }
public void Update(TEntity entity) {}
public async Task<TEntity> FindAsync( params object[] keyValues ) { return await Task.FromResult(default(TEntity)); }
public async Task<TEntity> FindAsync( CancellationToken cancellationToken, params object[] keyValues ) { return await Task.FromResult(default(TEntity)); }
public async Task<bool> DeleteAsync( params object[] keyValues ) { return await Task.FromResult(true); }
public async Task<bool> DeleteAsync( CancellationToken cancellationToken, params object[] keyValues ) { return await Task.FromResult(true); }
public class Repository<TDataContextToken, TEntity> : Repository<TEntity>, IRepository<TDataContextToken, TEntity> where TEntity : EntityBase where TDataContextToken : IDataContextToken
public Repository(IDataContext<TDataContextToken> dataContext) : base(dataContext)
public interface IUnitOfWork : IDisposable
string DataContextToken { get; }
Task SaveChangesAsync(CancellationToken cancellationToken);
public interface IUnitOfWork<TDataContextToken> : IUnitOfWork where TDataContextToken : IDataContextToken
public class UnitOfWork : IUnitOfWork
private readonly IDataContext _dataContext;
public UnitOfWork(IDataContext dataContext)
{ _dataContext = dataContext; }
public string DataContextToken { get { return _dataContext.DataContextToken; } }
Console.WriteLine("SaveChanges called on unit of work with context: " + DataContextToken);
_dataContext.SaveChanges();
public Task SaveChangesAsync(CancellationToken cancellationToken) { return Task.Delay(0); }
public Task SaveChangesAsync() { return Task.Delay(0); }
public class UnitOfWork<TDataContextToken> : UnitOfWork, IUnitOfWork<TDataContextToken> where TDataContextToken : IDataContextToken
public UnitOfWork(IDataContext<TDataContextToken> dataContext) : base(dataContext)
public interface IDataContextToken
public class MasterDataContextToken : IDataContextToken
public const string Token = "MasterDb";
public class Group1DataContextToken : IDataContextToken
public const string Token = "Group1";
public class Group2DataContextToken : IDataContextToken
public const string Token = "Group2";
public class Group3DataContextToken : IDataContextToken
public const string Token = "Group3";
public interface IUnitOfWorkManager
IUnitOfWork GetUnitOfWork(string token);
public class UnitOfWorkManager : IUnitOfWorkManager
private readonly IUnitOfWork[] _allUnitsOfWork;
public UnitOfWorkManager(params IUnitOfWork[] allUnitsOfWork)
_allUnitsOfWork = allUnitsOfWork;
public IUnitOfWork GetUnitOfWork(string token)
var unitOfWork = _allUnitsOfWork.FirstOrDefault(uow => uow.DataContextToken == token);
throw new ArgumentException("Unable to find unit of work with token: " + token, "token");
public interface IRepositoryManager<TEntity> where TEntity : EntityBase
IRepository<TEntity> GetRepository(string token);
public class RepositoryManager<TEntity> : IRepositoryManager<TEntity> where TEntity : EntityBase
private readonly IRepository<TEntity>[] _allRepositories;
public RepositoryManager(params IRepository<TEntity>[] allRepositories)
_allRepositories = allRepositories;
public IRepository<TEntity> GetRepository(string token)
var repository = _allRepositories.FirstOrDefault(rep => rep.DataContextToken == token);
throw new ArgumentException("Unable to find repository with token: " + token, "token");