2016-03-14 24 views
0

几天前我开始学习使用Unity的存储库模式时,我的印象是这种模式的主要好处是将数据层与业务层分离。存储库模式通用应用程序

换句话说,如果需要改变方式,应用程序如何存储数据,这是非常容易的,因为只有一个主模型负责通信。

这意味着,如果应用程序当前将数据保存到序列化的XML文件中,则改变此逻辑以连接到数据库不会很困难。

我发现几个很好的演示也使用Unit Of Work层,这看起来非常方便。让我告诉你一些我的代码。

public class UnitOfWork : IUnitOfWork 
{ 
    private readonly RepositoryContext _context; 
    public IEmployeeRepository Employees { get; set; } 

    public UnitOfWork(RepositoryContext context) 
    { 
     _context = context; 
     Employees = new EmployeeRepository(_context); 
    } 


    public int Complete() 
    { 
     return _context.SaveChanges(); 
    } 

    public void Dispose() 
    { 
     _context.Dispose(); 
    } 
} 

主要库上下文:

public class RepositoryContext : DbContext 
{ 
    public RepositoryContext() : base("name=RepositoryContext") 
    { 
    } 

    public virtual DbSet<Employee> Employees { get; set; } 
    public virtual DbSet<Equipment> Furniture { get; set; } 
} 

这里是演示EmployeeRepository:从一个普通的Repository它看起来像这样

public class EmployeeRepository:Repository<Employee>, IEmployeeRepository 
{ 
    public EmployeeRepository(RepositoryContext context) : base(context) { } 

    public Employee GetEmployeeByName(string sName) 
    { 
     return MyContext.Employees.FirstOrDefault(n => n.Name == sName); 
    } 

    public RepositoryContext MyContext 
    { 
     get { return Context as RepositoryContext; } 
    } 
} 

员工库导出:

public class Repository<T> : Interfaces.Repositories.IRepository<T> where T : class 
{ 
    protected readonly DbContext Context; 

    public Repository(DbContext context) 
    { 
     Context = context; 
    } 

    public void Add(T item) 
    { 
     Context.Set<T>().Add(item); 
    } 

    public IEnumerable<T> Find(Expression<Func<T, bool>> predicate) 
    { 
     return Context.Set<T>().Where(predicate); 
    } 

    public T Get(int ID) 
    { 
     return Context.Set<T>().Find(ID); 
    } 

    public IEnumerable<T> GetAll() 
    { 
     return Context.Set<T>().ToList(); 
    } 

    public void Remove(T item) 
    { 
     Context.Set<T>().Remove(item); 
    } 
} 

这里有一个问题:

至于我的理解去,我们是直接宣称,这下我们在它的构造DbContext,这是继在所有Add/Remove/Find函数特定类下使用Repository预期。

目前这个模型正在与数据库进行通信,但是如果我想要(不管什么原因)改变这个模型来保存XML文件中的数据,我将不得不完全重写我所有的Repository类?或者我在这里错过了什么?

如果我错了,它很容易做到,任何人都可以告诉我如何更改代码,以便我们将值序列化到XML文件中吗?我试图更好地理解这个版本库模式,但现在对我来说这是一个很大的混乱。

任何关于此事的帮助/建议将不胜感激。

+1

如果改变存储数据的方式,可能需要重新编写存储库类(这显然是预期的),但不是IRepository的使用者,因为接口保持不变,无论数据如何存储。所以你不需要改变业务类,这就是所谓的“从业务层分离数据层”。 –

回答

0

我读了一个问题,这样的:

我怎么能抽象的DbContext因此不存在依赖关系呢?

我会将上下文抽象到接口中以努力包含Dependency inversion principle

public interface IDbContext : IDisposable 
{ 
    int SaveChanges(); 
    IDbSet<Employee> Employees { get; set; } 
    IDbSet<Equipment> Furniture { get; set; } 
} 

public class RepositoryContext : DbContext, IDbContext 
{ 
    public RepositoryContext() : base("name=RepositoryContext") 
    { 
    } 

    public virtual DbSet<Employee> Employees { get; set; } 
    public virtual DbSet<Equipment> Furniture { get; set; } 
} 

然后尝试注入IDbContext接口。正如你的评论中提到的那样,你可能需要重写你的repo的部分内容,但是如果新的数据层可以暴露一个IDbSet,你应该能够简单地改变IDbContext的实现。

public class Repository<T> : Interfaces.Repositories.IRepository<T> where T : class 
{ 
    protected readonly IDbContext Context; 

    public Repository(IDbContext context) 
    { 
     Context = context; 
    } 

    public void Add(T item) 
    { 
     Context.Set<T>().Add(item); 
    } 

    public IEnumerable<T> Find(Expression<Func<T, bool>> predicate) 
    { 
     return Context.Set<T>().Where(predicate); 
    } 

    public T Get(int ID) 
    { 
     return Context.Set<T>().Find(ID); 
    } 

    public IEnumerable<T> GetAll() 
    { 
     return Context.Set<T>().ToList(); 
    } 

    public void Remove(T item) 
    { 
     Context.Set<T>().Remove(item); 
    } 
} 

我还会考虑在独立的类中抽象创建上下文的可能性。这里提到:Entity Framework using Repository Pattern, Unit of Work and Unity

public interface IDbContextFactory 
{ 
    IDbContext GetContext(); 
} 

public class DbContextFactory : IDbContextFactory 
{ 
    private readonly IDbContext _context; 

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

    public IDbContext GetContext() 
    { 
     return _context; 
    } 
} 

这样你就可以注入到IDbContextFactory工作单元。然后,您已将DbContext抽象为DbContextFactory,但您仍对DbContextFactoryDbContext有依赖关系。这对大多数人来说已经足够了,但是如果你真的想去SOLID,那么你可以用通用的IInstanceFactory来抽象。

public interface IDbContextFactory 
    { 
     /// <summary> 
     /// Creates a new context. 
     /// </summary> 
     /// <returns></returns> 
     IDbContext GenerateContext(); 

     /// <summary> 
     /// Returns the previously created context. 
     /// </summary> 
     /// <returns></returns> 
     IDbContext GetCurrentContext(); 
    } 

    public class DbContextFactory : IDbContextFactory 
    { 
     private readonly IInstanceFactory _instanceFactory; 
     private IDbContext _context; 

     public DbContextFactory(IInstanceFactory instanceFactory) 
     { 
      _instanceFactory = instanceFactory; 
     } 

     public IDbContext GenerateContext() 
     { 
      _context = _instanceFactory.CreateInstance<IDbContext>(); 
      return _context; 
     } 

     public IDbContext GetCurrentContext() 
     { 
      if (_context == null) 
       _context = GenerateContext(); 
      return _context; 
     } 
    } 

    /// <summary> 
    /// Creates an instance of a specific model. 
    /// </summary> 
    public interface IInstanceFactory 
    { 
     /// <summary> 
     /// Creates an instance of type T. 
     /// </summary> 
     T CreateInstance<T>(); 
    } 

    /// <summary> 
    /// Creates an instance based on the model defined by Unity. 
    /// </summary> 
    public class InstanceFactory : IInstanceFactory 
    { 
     private readonly IDictionary<Type, Func<object>> _funcs; 

     public InstanceFactory(IEnumerable<Func<object>> createFunc) 
     { 
      // To remove the dependency to Unity we will receive a list of funcs that will create the instance. 

      _funcs = new Dictionary<Type, Func<object>>(); 

      foreach (var func in createFunc) 
      { 
       var type = func.Method.ReturnType; 
       _funcs.Add(type, func); 
      } 
     } 

     /// <summary> 
     /// Creates an instance of T. 
     /// </summary> 
     /// <typeparam name="T"></typeparam> 
     /// <returns></returns> 
     public T CreateInstance<T>() 
     { 
      var func = _funcs[typeof(T)]; 
      return (T) func(); 
     } 
    } 

在我的统一登记:

container.RegisterType<IDbContext, YourDbContext>(new TransientLifetimeManager()); 
    container.RegisterType<IInstanceFactory, InstanceFactory>(
      new InjectionConstructor(new List<Func<object>> 
      { 
       new Func<IDbContext>(() => container.Resolve<IDbContext>()) 
      } 
     )); 

现在你已经提取了DbContext一路到了IoC,这在理论上可以在web.config中进行更改,甚至没有重新建设。注意事项?那么,考虑可读性与可维护性。我更喜欢一个真正抽象的层,而另一些人则认为这不是必需的,因为EF已经是一个工作单元模式。此外,可能会有性能开销,而不是像现在这样创建DbContext。从更哲学的角度来看,人们可能会争辩说,DbContext的抽象将是一个工作单元本身,因为它现在处于抽象层,可以像工作单元一样“传递”到一个SaveChanges()。但我把这个讨论留给你...

大部分这是手写的,但我希望它会帮助你的方式,如果你决定也抽象的DbContext。

编辑: 添加SaveChanges()到IDbContext