我整理了一份关于我如何使用工作单位的样本。存储库模式基于我的理解。如果我以正确的方式实施这个,请问有谁能告诉我吗?如果我不是,我该如何改进呢?
在此先感谢,非常感谢。
我有一个带有两个实体的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);
}
}
基本上我想确保以正确的方式访问数据并确保我不会忽略任何内容。再次,谢谢!
答案 0 :(得分:8)
将UnitOfWork实现为静态类并不完美。 定义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 所以控制器之间的依赖关系&lt; - &gt; repo&lt; - &gt; 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是最简单的。
希望它会有所帮助。