我整理了一份关于我如何使用工作单元的样本.存储库模式基于我的理解.如果我以正确的方式实施这个,请问有谁能告诉我吗?如果我不是,我该如何改进呢?
在此先感谢,非常感谢.
我有一个带有两个实体的EF模型:Topic和Subtopic. EF模型称为CommonGood.
工作单位:
/// <summary> /// Implementation of a UnitOfWork class /// </summary> public static class UnitOfWork { /// <summary> /// Gets the default context /// </summary> /// <returns>A new instance of the default context</returns> public static CommonGoodEntities GetContext() { return new CommonGoodEntities(); } }
IGenericRepository:
public interface IRepository<T> { /// <summary> /// Gets all entities /// </summary> /// <returns>All entities</returns> IEnumerable<T> GetAll(); /// <summary> /// Gets all entities matching the predicate /// </summary> /// <param name="predicate">The filter clause</param> /// <returns>All entities matching the predicate</returns> IEnumerable<T> GetAll(Expression<Func<T,bool>> predicate); /// <summary> /// Set based on where condition /// </summary> /// <param name="predicate">The predicate</param> /// <returns>The records matching the given condition</returns> IQueryable<T> Where(Expression<Func<T,bool>> predicate); /// <summary> /// Finds an entity matching the predicate /// </summary> /// <param name="predicate">The filter clause</param> /// <returns>An entity matching the predicate</returns> IEnumerable<T> Find(Expression<Func<T,bool>> predicate); /// <summary> /// Determines if there are any entities matching the predicate /// </summary> /// <param name="predicate">The filter clause</param> /// <returns>True if a match was found</returns> bool Any(Expression<Func<T,bool>> predicate); /// <summary> /// Returns the first entity that matches the predicate /// </summary> /// <param name="predicate">The filter clause</param> /// <returns>An entity matching the predicate</returns> T First(Expression<Func<T,bool>> predicate); /// <summary> /// Returns the first entity that matches the predicate else null /// </summary> /// <param name="predicate">The filter clause</param> /// <returns>An entity matching the predicate else null</returns> T FirstOrDefault(Expression<Func<T,bool>> predicate); /// <summary> /// Adds a given entity to the context /// </summary> /// <param name="entity">The entity to add to the context</param> void Add(T entity); /// <summary> /// Deletes a given entity from the context /// </summary> /// <param name="entity">The entity to delete</param> void Delete(T entity); /// <summary> /// Attaches a given entity to the context /// </summary> /// <param name="entity">The entity to attach</param> void Attach(T entity); }
通用存储库:
public class GenericRepository<T> : IRepository<T> where T : class { /// <summary> /// The database context for the repository /// </summary> private DbContext _context; /// <summary> /// The data set of the repository /// </summary> private IDbSet<T> _dbSet; /// <summary> /// Initializes a new instance of the <see cref="GenericRepository{T}" /> class. /// </summary> /// <param name="context">The context for the repository</param> public GenericRepository(DbContext context) { this._context = context; this._dbSet = this._context.Set<T>(); } /// <summary> /// Gets all entities /// </summary> /// <returns>All entities</returns> public IEnumerable<T> GetAll() { return this._dbSet; } /// <summary> /// Gets all entities matching the predicate /// </summary> /// <param name="predicate">The filter clause</param> /// <returns>All entities matching the predicate</returns> public IEnumerable<T> GetAll(System.Linq.Expressions.Expression<Func<T,bool>> predicate) { return this._dbSet.Where(predicate); } /// <summary> /// Set based on where condition /// </summary> /// <param name="predicate">The predicate</param> /// <returns>The records matching the given condition</returns> public IQueryable<T> Where(Expression<Func<T,bool>> predicate) { return this._dbSet.Where(predicate); } /// <summary> /// Finds an entity matching the predicate /// </summary> /// <param name="predicate">The filter clause</param> /// <returns>An entity matching the predicate</returns> public IEnumerable<T> Find(System.Linq.Expressions.Expression<Func<T,bool>> predicate) { return this._dbSet.Where(predicate); } /// <summary> /// Determines if there are any entities matching the predicate /// </summary> /// <param name="predicate">The filter clause</param> /// <returns>True if a match was found</returns> public bool Any(Expression<Func<T,bool>> predicate) { return this._dbSet.Any(predicate); } /// <summary> /// Returns the first entity that matches the predicate /// </summary> /// <param name="predicate">The filter clause</param> /// <returns>An entity matching the predicate</returns> public T First(Expression<Func<T,bool>> predicate) { return this._dbSet.First(predicate); } /// <summary> /// Returns the first entity that matches the predicate else null /// </summary> /// <param name="predicate">The filter clause</param> /// <returns>An entity matching the predicate else null</returns> public T FirstOrDefault(Expression<Func<T,bool>> predicate) { return this._dbSet.FirstOrDefault(predicate); } /// <summary> /// Adds a given entity to the context /// </summary> /// <param name="entity">The entity to add to the context</param> public void Add(T entity) { this._dbSet.Add(entity); } /// <summary> /// Deletes a given entity from the context /// </summary> /// <param name="entity">The entity to delete</param> public void Delete(T entity) { this._dbSet.Remove(entity); } /// <summary> /// Attaches a given entity to the context /// </summary> /// <param name="entity">The entity to attach</param> public void Attach(T entity) { this._dbSet.Attach(entity); } }
控制器:
public class HomeController : Controller { /// <summary> /// The context used for the controller /// </summary> private DbContext _context; /// <summary> /// Initializes a new instance of the <see cref="HomeController"/> class. /// </summary> public HomeController() { this._context = UnitOfWork.GetContext(); } public JsonResult GetTopics() { var topics = new GenericRepository<Topic>(this._context).GetAll().ToList(); return this.Json(topics,JsonRequestBehavior.AllowGet); } /// <summary> /// Disposes of the context if the currently disposing /// </summary> /// <param name="disposing">A value indicating whether or not the application is disposing</param> protected override void Dispose(bool disposing) { if (disposing) { this._context.Dispose(); } base.Dispose(disposing); } }
基本上我想确保我以正确的方式访问数据并确保我没有忽略任何东西.再次,谢谢!
解决方法
将UnitOfWork实现为静态类并不完美.
定义IUnitOfWork接口.您的db上下文将实现此接口.
它可能看起来像:
定义IUnitOfWork接口.您的db上下文将实现此接口.
它可能看起来像:
public interface IUnitOfWork { int SaveChanges(); } public class EFDbContext: DbContext,IUnitOfWork { public DbSet<User> User { get; set; } public EFDbContext(string connectionString) : base(connectionString) { } public override int SaveChanges() { return base.SaveChanges(); } }
我通常创建从通用存储库继承的几个存储库.因此,存储库查找方法的名称可以具有更具体的名称.这还可以防止在不同控制器中重复存储库逻辑.
例如:
public class EFUserRepository: EFRepository<User>,IUserRepository { public EFUserRepository(IUnitOfWork context) : base(context) { } protected override DbSet<User> Table { get { return Context.User; } } public User Find(string email) { return Table.FirstOrDefault(u => u.Email == email); } public bool Validate(string email,string password) { string passwordHash = Cryptography.GenerateHash(password); User user = Find(email); return user != null && user.Password == passwordHash; }
现在关于控制器:为了简化测试,最好使用IoC Container,例如: NInject
所以控制器之间的依赖关系< - > repo< - > unitOfWork将由NInject解决.
这怎么可以用Login方法看看UserController:
public class UserController: Controller { [Ninject.Inject] public IUserRepository UserRepository { get; set; } public ActionResult Login(Authorizationviewmodel vm) { if(ModelState.IsValid) { if(UserRepository.Validate(vm.Email,vm.Password)) { FormsAuthentication.SetAuthCookie(vm.Email,true); if(Url.IsLocalUrl(vm.ReturnUrl)) { return Redirect(vm.ReturnUrl); } else { return RedirectToAction("Page","Main"); } } else { ModelState.AddModelError("",Resources.Validation.WrongEmailOrPassword); } } return View(vm); } }
依赖关系解析可以由自定义控制器工厂完成,如下所示:
public class NInjectControllerFactory: DefaultControllerFactory { public IKernel Kernel { get; private set; } public NInjectControllerFactory() { Kernel = new StandardKernel(); AddBindings(); } protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext,Type controllerType) { return controllerType == null ? null : (IController)Kernel.Get(controllerType); } private void AddBindings() { Kernel.Bind<IUnitOfWork>().To(typeof(EFDbContext)).InRequestScope(); Kernel.Bind<IUserRepository>().To(typeof(EFUserRepository).InRequestScope(); } }
并使用您的自定义替换当前控制器工厂.您可以在Global.asax的Application_Start处理程序中执行此操作:
protected void Application_Start() { ... ControllerBuilder.Current.SetControllerFactory(new NInjectControllerFactory()); }
如果你决定使用NInject,你可以简单地用Nuget添加它.要启用绑定InRequestScope,您还需要NInject.Web.Common.当然,还有许多其他选择,如Castle Windsor或StructureMap,但NInject是最简单的选择.
希望它会有所帮助.