[英]Repository Pattern universal application
幾天前,當我開始使用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:
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; }
}
}
員工存儲庫派生自一個通用Repository
,如下所示:
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);
}
}
這是問題:
就我的理解而言,我們直接聲明,在我們的Repository
中,它需要構造函數DbContext
,該構造DbContext
隨后Add / Remove / Find
在該特定類下的所有Add / Remove / Find
函數中使用。
當前,該模型正在與數據庫通信,但是如果我出於某種原因想要更改此模型以將數據保存在XML文件中,則必須完全重寫所有的Repository
類嗎? 還是我在這里想念什么?
如果我錯了並且很容易做到,請問有人可以告訴我如何更改代碼,以便我們將值序列化為XML文件嗎? 我試圖更好地理解這種存儲庫模式,但是現在對我來說這是一個很大的混亂。
關於此事的任何幫助/建議將不勝感激。
我正在閱讀這樣的問題:
我如何抽象DbContext以便沒有依賴關系?
我將把上下文抽象到接口,以嘗試采用依賴關系反轉原則 。
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
接口。 如評論中所述,您可能仍然需要重寫部分倉庫,但是如果新的數據層可以公開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);
}
}
我還將研究在單獨的類中抽象上下文創建的可能性。 如此處所述: 使用存儲庫模式,工作單元和統一性的實體框架
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
{
/// <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();
}
}
在我的Unity注冊中:
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
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.