How to inject my dbContext with Unity

后端 未结 3 476
Happy的楠姐
Happy的楠姐 2021-01-12 01:23

How do I inject my dbContext class using Unity? I can\'t just create a Interface like for my other \"normal\" classes? What should I do with my RequestContext class and what

3条回答
  •  伪装坚强ぢ
    2021-01-12 01:41

    I'm solving this problem with DbContext.Set() method, DbContext wrapper class and generics.

    I have IRepositoryContext interface and RepositoryContext to wrap my DbContext:

    public interface IRepositoryContext
    {
        DbContext DbContext { get; }
    
        /// 
        /// Commit data.
        /// 
        void Save();
    }
    
    public class RepositoryContext : IRepositoryContext
    {
        private readonly DbContext _dbContext;
    
        public RepositoryContext(DbContext dbContext)
        {
            _dbContext = dbContext;
        }
    
        public DbContext DbContext { get { return _dbContext; } }
    
        public void Save()
        {
            _dbContext.SaveChanges();
        }
    }
    

    Ok, then I write bas implementation of generic repository:

     public abstract class RepositoryBase : IRepository
        where TEntity : class , IEntity, IRetrievableEntity
        where TId : struct
    {
        protected readonly IRepositoryContext RepositoryContext;
        protected readonly DbContext Context;
    
        protected RepositoryBase(IRepositoryContext repositoryContext)
        {
            RepositoryContext = repositoryContext;
        }
    
        public DbSet Data { get { return RepositoryContext.DbContext.Set(); }
    
        public TEntity Get(TId id)
        {
            return Data.Find(id);
        }
    
        public virtual IList GetAll()
        {
            return Data.ToList();
        }
    
        public virtual TEntity Save(TEntity entity)
        {
            try
            {
                var state = entity.Id.Equals(default(TId)) ? EntityState.Added : EntityState.Modified;
                RepositoryContext.DbContext.Entry(entity).State = state;
                RepositoryContext.Save();
                return entity;
            }
            catch (DbEntityValidationException e)
            {
                throw ValidationExceptionFactory.GetException(e);
            }
        }
    
        public virtual void Delete(TEntity entity)
        {
            if (entity == null) return;
            Data.Remove(entity);
            Context.SaveChanges();
        }
    
        public void Commit()
        {
            RepositoryContext.Save();
        }
    
        public IList Get(Expression> criteria)
        {
            return Data.Where(criteria).ToList();
        }
    
        // some other base stuff here
    }
    

    Ok, now I can register my DbContext with next extension methods:

    public static class RikropCoreDataUnityExtensions
    {
        #region Const
    
        private readonly static Type _repositoryInterfaceType = typeof(IRepository<,>);
        private readonly static Type _deactivatableRepositoryInterfaceType = typeof(IDeactivatableRepository<,>);
        private readonly static Type _deactivatableEntityType = typeof(DeactivatableEntity<>);
        private readonly static Type _retrievableEntityType = typeof(IRetrievableEntity<,>);
    
        #endregion Const
    
        #region public methods
    
        /// 
        /// Register wrapper class.
        /// 
        /// DbContext type.
        /// Unity-container.
        public static void RegisterRepositoryContext(this IUnityContainer container)
            where TContext : DbContext, new()
        {
            container.RegisterType(new InjectionFactory(c => new RepositoryContext(new TContext())));
        }
    
        /// 
        /// Register wrapper class.
        /// 
        /// DbContext type.
        /// Unity-container.
        /// DbContext constructor.
        /// Connection string name.
        public static void RegisterRepositoryContext(this IUnityContainer container,
            Func contextConstructor, string connectionString)
            where TContext : DbContext
        {
            container.RegisterType(
                new InjectionFactory(c => new RepositoryContext(contextConstructor(connectionString))));
        }
    
        /// 
        /// Automatically generation and registration for generic repository marked by attribute.
        /// 
        /// Unity-container.
        /// Assembly with repositories marked with RepositoryAttribute.
        public static void RegisterCustomRepositories(this IUnityContainer container, Assembly assembly)
        {
            foreach (var repositoryType in assembly.GetTypes().Where(type => type.IsClass))
            {
                var repositoryAttribute = repositoryType.GetCustomAttribute();
                if (repositoryAttribute != null)
                {
                    container.RegisterType(
                        repositoryAttribute.RepositoryInterfaceType, 
                        repositoryType,
                        new TransientLifetimeManager());
                }
            }
        }
    
        /// 
        /// Automatically generation and registration for generic repository for all entities.
        /// 
        /// Unity-container.
        /// Assembly with Entities which implements IRetrievableEntity.
        public static void RegisterRepositories(this IUnityContainer container, Assembly assembly)
        {
            foreach (var entityType in assembly.GetTypes().Where(type => type.IsClass))
            {
                if (!entityType.InheritsFromGeneric(_retrievableEntityType))
                    continue;
    
                Type[] typeArgs = entityType.GetGenericTypeArguments(_retrievableEntityType);
                Type constructedRepositoryInterfaceType = _repositoryInterfaceType.MakeGenericType(typeArgs);
                container.RegisterRepository(constructedRepositoryInterfaceType);
    
                if (entityType.InheritsFrom(_deactivatableEntityType.MakeGenericType(new[] { typeArgs[1] })))
                {
                    var constructedDeactivatableRepositoryInterfaceType =
                        _deactivatableRepositoryInterfaceType.MakeGenericType(typeArgs);
                    container.RegisterRepository(constructedDeactivatableRepositoryInterfaceType);
                }
            }
        }
    
        #endregion public methods
    
        #region private methods
    
        /// 
        /// Generate and register repository.
        /// 
        /// Unity-container.
        /// Repository interface type.
        private static void RegisterRepository(this IUnityContainer container, Type repositoryInterfaceType)
        {
            var factoryGenerator = new RepositoryGenerator();
            var concreteFactoryType = factoryGenerator.Generate(repositoryInterfaceType);
            container.RegisterType(
                repositoryInterfaceType,
                new TransientLifetimeManager(),
                new InjectionFactory(
                    c =>
                    {
                        var activator = new RepositoryActivator();
                        return activator.CreateInstance(c, concreteFactoryType);
                    }));
        }
    
        #endregion private methods
    }
    

    Finally you can just resolve IRepository on your classes. You just need to register your RepositoryContext:

    container.RegisterRepositoryContext();
    //container.RegisterRepositoryContext(s => new MyDbContext(s), "myConStr");
    

    And your repository will resolve IRepositoryContext and you can have access to DbSet and other DbContext members via IRepositoryContext property.

    You can use full source code for repositories, Unity-helpers on Github.

提交回复
热议问题