Smooth.IoC.Dapper.Repository.UnitOfWork icon indicating copy to clipboard operation
Smooth.IoC.Dapper.Repository.UnitOfWork copied to clipboard

Implemented repository factory

Open mcinnes01 opened this issue 6 years ago • 6 comments

Implemented repository factory and provided unity example for usage in readme

mcinnes01 avatar Jun 21 '18 14:06 mcinnes01

Example usage:

var person = await uow.GetRepository<IPersonRepository>().GetPersonDetailsAsync(id);

mcinnes01 avatar Jun 21 '18 14:06 mcinnes01

I've kept the IOC abstract like you have, just haven't provided an example implementation of each, sadly I'm using unity so I had a specific example but you could simply do the same e.g. Autofac would be:

public class AutofacRegistrar
{
    public void Register(ContainerBuilder builder)
    {
        builder.Register(c=> new AutofacDbFactory(c.Resolve<IComponentContext>())).As<IDbFactory>().SingleInstance();
        builder.Register(c=> new AutofacRepositoryFactory(c.Resolve<IComponentContext>())).As<IRepositoryFactory>().SingleInstance();
        builder.RegisterType<Dapper.Repository.UnitOfWork.Data.UnitOfWork>().As<IUnitOfWork>();
    }

    sealed class AutofacDbFactory : IDbFactory
    {
        private readonly IComponentContext _container;
        public AutofacDbFactory(IComponentContext container)
        {
            _container = container;
        }
        public T Create<T>() where T : class, ISession
        {
            return _container.Resolve<T>();
        }
        public TUnitOfWork Create<TUnitOfWork, TSession>(IsolationLevel isolationLevel = IsolationLevel.Serializable) where TUnitOfWork : class, IUnitOfWork where TSession : class, ISession
        {
            return _container.Resolve<TUnitOfWork>(
	            new ParameterOverride("factory", _container.Resolve<IDbFactory>()),
	            new ParameterOverride("repositoryFactory", _container.Resolve<IRepositoryFactory>()),
                new ParameterOverride("session", Create<TSession>()),
	            new ParameterOverride("isolationLevel", isolationLevel),
	            new ParameterOverride("sessionOnlyForThisUnitOfWork", true));
        }
        public T Create<T>(IDbFactory factory, IRepositoryFactory repositoryFactory, ISession session, IsolationLevel isolationLevel = IsolationLevel.Serializable) where T : class, IUnitOfWork
        {
            return _container.Resolve<T>(
	            new ParameterOverride("factory", factory),
	            new ParameterOverride("repositoryFactory", repositoryFactory),
                new ParameterOverride("session", session),
	            new ParameterOverride("isolationLevel", isolationLevel),
	            new ParameterOverride("sessionOnlyForThisUnitOfWork", false));
        }
        public void Release(IDisposable instance)
        {
            instance.Dispose();
        }
    }

    sealed class AutofacRepositoryFactory : IRepositoryFactory
    {
        private readonly IComponentContext _container;
        public AutofacDbFactory(IComponentContext container)
        {
            _container = container;
        }
        public TRepository GetRepository<TRepository>(IUnitOfWork uow) where TRepository : IRepository
        {
            return _container.Resolve<TRepository>(
                new ParameterOverride("uow", uow)
            );
        }
    }
}

Just trying something out, to see if I can't just inject the repository factory just in to the unit of work, which would decouple it from session...

mcinnes01 avatar Jun 21 '18 18:06 mcinnes01

Ok, so yes you can decouple the repository factory from the session and it still works with the unit of work. I've update the PR.

mcinnes01 avatar Jun 21 '18 19:06 mcinnes01

@mcinnes01 Thanks !:-) I need to have and deeper look at this. We also need to think about the disposal of the repos, e.g.windsor needs you to dispose factory created items as it does not track it (unless Singleton).

Please give me a little time. Have a good evening...

generik0 avatar Jun 21 '18 20:06 generik0

Hi @mcinnes01 Sorry for the long wait. I have been Working days and nights these days :-). Uat busy you know...

If you look under the test examples with IOC installeres you can e.g. see that Autofac uses register genetics with the repository, and castle windsor has a registration with IRepository<>. For these IoCs it means that you can ctor inject the IRepository with any entity you like. Essentially the factory you wanted. Does Unity not have such a registration possibility?

generik0 avatar Jun 28 '18 05:06 generik0

I think this will do it in unity:

container.RegisterType(typeof(IRepository<>), typeof(Repository <>), new TransientLifetimeManager());

generik0 avatar Jun 28 '18 05:06 generik0