存储库模式通用应用程序
几天前,当我开始学习使用Unity的Repository Pattern时,我觉得这种模式的主要好处是数据层与业务层的分离。
换句话说,如果需要改变方式,应用程序如何存储数据,这很容易,因为只有一个主模型负责通信。
这意味着,如果应用程序当前将数据保存到序列化的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 Employees { get; set; } public virtual DbSet Furniture { get; set; } }
这是演示EmployeeRepository:
public class EmployeeRepository:Repository, 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; } } }
Employee Repository派生自一个通用的Repository
,如下所示:
public class Repository : Interfaces.Repositories.IRepository where T : class { protected readonly DbContext Context; public Repository(DbContext context) { Context = context; } public void Add(T item) { Context.Set().Add(item); } public IEnumerable Find(Expression<Func> predicate) { return Context.Set().Where(predicate); } public T Get(int ID) { return Context.Set().Find(ID); } public IEnumerable GetAll() { return Context.Set().ToList(); } public void Remove(T item) { Context.Set().Remove(item); } }
这是一个问题:
据我所知,我们直接声明,在我们的Repository
期望它的构造函数DbContext
,后来在该特定类下的所有Add / Remove / Find
函数下使用。
目前这个模型正在与数据库进行通信,但如果我想(无论出于何种原因)更改此模型以将数据保存在XML文件中,我将不得不完全重写所有的Repository
类? 或者我在这里遗漏了什么?
如果我错了并且很容易实现,那么有人可以告诉我如何更改代码以便我们将值序列化到XML文件中吗? 我试图更好地理解这个存储库模式,但是现在它对我来说是一个很大的混乱。
任何有关此事的帮助/建议都将受到高度赞赏。
我正在读这个问题:
我如何抽象DbContext,以便它没有依赖?
我会将上下文抽象到接口,以便接受依赖性反转原则 。
public interface IDbContext : IDisposable { int SaveChanges(); IDbSet Employees { get; set; } IDbSet Furniture { get; set; } } public class RepositoryContext : DbContext, IDbContext { public RepositoryContext() : base("name=RepositoryContext") { } public virtual DbSet Employees { get; set; } public virtual DbSet Furniture { get; set; } }
然后尝试注入IDbContext
接口。 正如您的评论中所提到的,您可能还需要重写部分repo,但如果新数据层可以公开IDbSet,您应该能够简单地更改IDbContext
的实现。
public class Repository : Interfaces.Repositories.IRepository where T : class { protected readonly IDbContext Context; public Repository(IDbContext context) { Context = context; } public void Add(T item) { Context.Set ().Add(item); } public IEnumerable Find(Expression> predicate) { return Context.Set ().Where(predicate); } public T Get(int ID) { return Context.Set ().Find(ID); } public IEnumerable GetAll() { return Context.Set ().ToList(); } public void Remove(T item) { Context.Set ().Remove(item); } }
我还会考虑在单独的类中抽象创建上下文的可能性。 如上所述: 使用存储库模式,工作单元和Unity的entity framework
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,但你仍然在DbContextFactory
对DbContext
有一个依赖。 这对大多数人来说已经足够了,但是如果你真的想去SOLID那么你也可以用通用的IInstanceFactory
来抽象它。
public interface IDbContextFactory { /// /// Creates a new context. /// /// IDbContext GenerateContext(); /// /// Returns the previously created context. /// /// 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(); return _context; } public IDbContext GetCurrentContext() { if (_context == null) _context = GenerateContext(); return _context; } } /// /// Creates an instance of a specific model. /// public interface IInstanceFactory { /// /// Creates an instance of type T. /// T CreateInstance(); } /// /// Creates an instance based on the model defined by Unity. /// public class InstanceFactory : IInstanceFactory { private readonly IDictionary> _funcs; public InstanceFactory(IEnumerable> createFunc) { // To remove the dependency to Unity we will receive a list of funcs that will create the instance. _funcs = new Dictionary>(); foreach (var func in createFunc) { var type = func.Method.ReturnType; _funcs.Add(type, func); } } /// /// Creates an instance of T. /// /// /// public T CreateInstance() { var func = _funcs[typeof(T)]; return (T) func(); } }
在我的Unity注册中:
container.RegisterType(new TransientLifetimeManager()); container.RegisterType( new InjectionConstructor(new List> { new Func(() => container.Resolve ()) } ));
现在你已经将DbContext
一直抽象到IoC,理论上可以在web.config中进行更改,甚至不需要重新构建。 注意事项? 好吧,考虑可读性和可维护性。 我更喜欢一个真正抽象的层,而其他人则认为没有必要,因为EF已经是一个工作单元模式。 此外,可能会有性能开销,而不是像现在一样创建DbContext
。 从更哲学的角度来看,人们可能认为DbContext的抽象将是一个工作单元本身,因为它现在处于抽象层,其中SaveChanges()
可以作为一个工作单元“传递”。 但是我把这个讨论留给你了……
大部分内容都是手工编写的,但如果您决定抽象DbContext,我希望它能帮助您。
编辑:将 SaveChanges()添加到IDbContext
。
上述就是C#学习教程:存储库模式通用应用程序分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/988651.html