如何使用Unity注入我的dbContext

And*_*ndy 7 c# asp.net-mvc entity-framework unity-container

如何使用Unity注入我的dbContext类?我不能只为我的其他"普通"类创建一个界面?我应该如何处理RequestContext类以及UnityConfig应该是什么样的?

public class RequestContext : IdentityDbContext<User>
    {
        public RequestContext()
            : base("DefaultConnection", throwIfV1Schema: false)
        {
            Database.SetInitializer<RequestContext>(new CreateDatabaseIfNotExists<RequestContext>());
        }

        public DbSet<Request> Requests { get; set; }
        public DbSet<Record> Records { get; set; }



        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
            base.OnModelCreating(modelBuilder);
        }

        public static RequestContext Create()
        {
            return new RequestContext();
        }
    }
Run Code Online (Sandbox Code Playgroud)

在我的Repository类中,我使用它,但是想要注入:

 private RequestContext dbContext;
 private IUserRepository _userRepository;

 public RequestRepository(IUserRepository userRepository)
 {
      dbContext = new RequestContext();
      _userRepository = userRepository;
 }
Run Code Online (Sandbox Code Playgroud)

Vad*_*nov 0

我正在用DbContext.Set<TEntity>()方法、DbContext包装类和泛型来解决这个问题。

我有IRepositoryContext接口并RepositoryContext包装我的 DbContext:

public interface IRepositoryContext
{
    DbContext DbContext { get; }

    /// <summary>
    /// Commit data.
    /// </summary>
    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();
    }
}
Run Code Online (Sandbox Code Playgroud)

好的,然后我编写通用存储库的基本实现:

 public abstract class RepositoryBase<TEntity, TId> : IRepository<TEntity, TId>
    where TEntity : class , IEntity<TId>, IRetrievableEntity<TEntity, TId>
    where TId : struct
{
    protected readonly IRepositoryContext RepositoryContext;
    protected readonly DbContext Context;

    protected RepositoryBase(IRepositoryContext repositoryContext)
    {
        RepositoryContext = repositoryContext;
    }

    public DbSet<TEntity> Data { get { return RepositoryContext.DbContext.Set<TEntity>(); }

    public TEntity Get(TId id)
    {
        return Data.Find(id);
    }

    public virtual IList<TEntity> 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<TEntity> Get(Expression<Func<TEntity, bool>> criteria)
    {
        return Data.Where(criteria).ToList();
    }

    // some other base stuff here
}
Run Code Online (Sandbox Code Playgroud)

好的,现在我可以使用下一个扩展方法注册我的 DbContext:

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

    /// <summary>
    /// Register wrapper class.
    /// </summary>
    /// <typeparam name="TContext">DbContext type.</typeparam>
    /// <param name="container">Unity-container.</param>
    public static void RegisterRepositoryContext<TContext>(this IUnityContainer container)
        where TContext : DbContext, new()
    {
        container.RegisterType<IRepositoryContext, RepositoryContext>(new InjectionFactory(c => new RepositoryContext(new TContext())));
    }

    /// <summary>
    /// Register wrapper class.
    /// </summary>
    /// <typeparam name="TContext">DbContext type.</typeparam>
    /// <param name="container">Unity-container.</param>
    /// <param name="contextConstructor">DbContext constructor.</param>
    /// <param name="connectionString">Connection string name.</param>
    public static void RegisterRepositoryContext<TContext>(this IUnityContainer container,
        Func<string, TContext> contextConstructor, string connectionString)
        where TContext : DbContext
    {
        container.RegisterType<IRepositoryContext, RepositoryContext>(
            new InjectionFactory(c => new RepositoryContext(contextConstructor(connectionString))));
    }

    /// <summary>
    /// Automatically generation and registration for generic repository marked by attribute.
    /// </summary>
    /// <param name="container">Unity-container.</param>
    /// <param name="assembly">Assembly with repositories marked with RepositoryAttribute.</param>
    public static void RegisterCustomRepositories(this IUnityContainer container, Assembly assembly)
    {
        foreach (var repositoryType in assembly.GetTypes().Where(type => type.IsClass))
        {
            var repositoryAttribute = repositoryType.GetCustomAttribute<RepositoryAttribute>();
            if (repositoryAttribute != null)
            {
                container.RegisterType(
                    repositoryAttribute.RepositoryInterfaceType, 
                    repositoryType,
                    new TransientLifetimeManager());
            }
        }
    }

    /// <summary>
    /// Automatically generation and registration for generic repository for all entities.
    /// </summary>
    /// <param name="container">Unity-container.</param>
    /// <param name="assembly">Assembly with Entities which implements IRetrievableEntity.</param>
    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

    /// <summary>
    /// Generate and register repository.
    /// </summary>
    /// <param name="container">Unity-container.</param>
    /// <param name="repositoryInterfaceType">Repository interface type.</param>
    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
}
Run Code Online (Sandbox Code Playgroud)

最后你就可以决定IRepository<EntityType>你的课程了。您只需注册您的RepositoryContext:

container.RegisterRepositoryContext<MyDbContext>();
//container.RegisterRepositoryContext(s => new MyDbContext(s), "myConStr");
Run Code Online (Sandbox Code Playgroud)

您的存储库将解析 IRepositoryContext,您可以通过属性访问DbSet<TEntity>其他DbContext 成员IRepositoryContext。

您可以使用Github 上的存储库、Unity-helpers的完整源代码。