2016-04-17 35 views
3

如何使用Unity注入我的dbContext类?我不能只为我的其他“普通”类创建一个接口?我应该如何处理我的RequestContext类以及我的UnityConfig应该如何?如何使用Unity注入我的dbContext

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(); 
     } 
    } 

在我的仓库类我这样使用它,但要改为注:

private RequestContext dbContext; 
     private IUserRepository _userRepository; 

     public RequestRepository(IUserRepository userRepository) 
     { 
      dbContext = new RequestContext(); 
      _userRepository = userRepository; 
     } 

回答

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(); 
    } 
} 

好吧,那么我写BAS实现通用仓库的:

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 
} 

好了,现在我可以在我的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 
} 

最后你ca ñ只需在您的课程上解决IRepository<EntityType>。你只需要注册您的RepositoryContext

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

而且你的仓库将解决IRepositoryContext,你可以有DbSet<TEntity>DbContext members通过IRepositoryContext属性访问。

您可以在Github上使用repositoriesUnity-helpers的完整源代码。

0

我通常用DbContextFactory来解决这个问题。这将允许您在需要时创建上下文,并在完成后进行处理。

public interface IDbContextFactory 
{ 
    IdentityDbContext<User> GetContext(); 
} 

public class DbContextFactory : IDbContextFactory 
{ 
    private readonly IdentityDbContext<User> _context; 

    public DbContextFactory() 
    { 
     _context = new RequestContext("ConnectionStringName"); 
    } 

    public IdentityDbContext<User> GetContext() 
    { 
     return _context; 
    } 
} 

该工厂可以很容易地注入。您可以在此处看到更完整的示例:Repository Pattern universal application

在工厂中,您还可以选择在构造函数或方法中创建DbContext。在使用Unity时,我建议您尽可能少地使用构造函数,因为Unity会为您解析整个链。这意味着每次存储库解析时都会创建DbContext。这将需要注入存储库的类还需要处置存储库(反过来应该处理DbContext),以及当两个类使用相同的存储库实例时会发生什么?这显然可以通过终生管理者和良好的编程实践来解决,但是我发现在需要时简单地打开和关闭上下文更为优雅。

示例的使用方法:

using (var context = _dbContextFactory.GenerateContext()) 
{ 
    return context.Requests.FirstOrDefault(x => x.Id == foo); 
} 

并为您的存储库更完整的示例:

public class RequestRepository 
{ 
    private IDbContextFactory _contextFactory; 

    public RequestRepository(IDbContextFactory contextFactory) 
    { 
     // DbContext will not be created in constructor, and therefore your repository doesn't have to implement IDisposable. 
     _contextFactory= contextFactory; 
    } 

    public Request FindById(int id) 
    { 
     // Context will be properly disposed thanks to using. 
     using (var context = _dbContextFactory.GenerateContext()) 
     { 
      return context.Requests.FirstOrDefault(x => x.Id == id); 
     } 
    } 
} 

当你创建你的界面为你的方面,我也可以推荐你将DbSet<T>更改为IDbSet<T>以允许更轻松地进行单元测试。接口示例为DbContext

public interface IDbContext : IDisposable, IObjectContextAdapter 
{ 
     IDbSet<Request> Requests { get; set; } 
     IDbSet<Record> Records { get; set; } 
     int SaveChanges(); 

     DbSet Set(Type entityType); 
     DbSet<TEntity> Set<TEntity>() where TEntity : class; 
} 

如果your're寻找注入DbContext在构造函数中,你也可以看看的Unit of Work-pattern,包装了DbContext,并允许几个类使用相同的情况下,在特定周期(如一个请求)。有人可能会争辩说EF已经实施了工作单元模式,但我再次讨论这个问题。下面是几个例子:

http://www.codeproject.com/Articles/741207/Repository-with-Unit-of-Work-IoC-and-Unit-Test

Onion Architecture, Unit of Work and a generic Repository pattern

相关问题