我试图在n层架构中实践松耦合和分离所有内容,但我坚持我所相信的基本内容。我的第一个问题是推荐信。我不断地在程序集之间移动类,因为类A需要类B,但无法到达它,所以让我们移动类B——然后我打破类c。
这是我能想出的最好的办法了。
步骤1:架构
项目。数据
- 实体(略)
项目。DataAccess
- <
- 上下文/gh><
- 迁移/gh><
- 存储库/gh>
- 工作单位
- 视图模型
项目。Web
- <
- 控制器/gh>
步骤2:使用Project。数据访问作为表示和数据之间的粘合剂
我正在使用工作单元模式,但这需要访问poco,所以我不能在控制器中使用UoW。因此,我认为创建名为ViewModelService
的包装器/服务将是一个很好的计划。这个服务实例化了UoW,并将automap Viewmodels返回给我的控制器。
我的UoW/Repository模式是通用的,所以我想让我的服务也通用。
<标题> IRepository h1>public interface IRepository<TObject>
{
IQueryable<TObject> All();
IQueryable<TObject> Filter(Expression<Func<TObject, bool>> predicate);
IQueryable<TObject> Filter<TKey>(Expression<Func<TObject, bool>> filter,
out int total, int index = 0, int size = 50);
bool Contains(Expression<Func<TObject, bool>> predicate);
TObject Find(params object[] keys);
TObject Find(Expression<Func<TObject, bool>> predicate);
TObject Create(TObject t);
int Delete(TObject t);
int Delete(Expression<Func<TObject, bool>> predicate);
int Update(TObject t);
void Ignore(TObject t);
int Count { get; }
}
<标题>通用BaseRepository h1> public class BaseRepository<TObject> : IRepository<TObject>
where TObject : class
{
protected AppDbContext Context = null;
public BaseRepository(AppDbContext context)
{
Context = context;
}
protected DbSet<TObject> DbSet
{
get { return Context.Set<TObject>(); }
}
public virtual int Count
{
get { return Queryable.Count<TObject>(DbSet); }
}
// ... (You get the picture)
}
<标题> UnitOfWork h1> public class UnitOfWork : IDisposable
{
private readonly AppDbContext _context = new AppDbContext();
private BaseRepository<Order> _orderRepository;
private BaseRepository<Product> _productRepository;
private BaseRepository<ApplicationUser> _userRepository;
private bool _disposed;
public BaseRepository<Order> OrderRepository
{
get
{
if (_orderRepository == null)
{
_orderRepository = new BaseRepository<Order>(_context);
}
return _orderRepository;
}
}
public BaseRepository<Product> ProductRepository
{
get
{
if (_productRepository == null)
{
_productRepository = new BaseRepository<Product>(_context);
}
return _productRepository;
}
}
public BaseRepository<ApplicationUser> UserRepository
{
get
{
if (_userRepository == null)
{
_userRepository = new BaseRepository<ApplicationUser>(_context);
}
return _userRepository;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Save()
{
_context.SaveChanges();
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_context.Dispose();
}
}
_disposed = true;
}
}
所以现在-没有"service"和新的n层-我在我的控制器中使用它。
public class ProductController : Controller
{
private UnitOfWork _unitOfWork = new UnitOfWork();
// GET: /Product/
[Route]
public ActionResult Index()
{
var model = _unitOfWork.ProductRepository.All();
return View(model);
}
// Etc...
但是现在我把所有东西都分成了单独的层,我不能那样做了。我不想让我的Unit of Work类映射ViewModels
下面是我创建这个"服务"的尝试(甚至不确定它的名字是否正确):
<标题> ViewModelService h1> public class ViewModelService : IViewModelService
{
private readonly UnitOfWork _unitOfWork = new UnitOfWork();
public T GetSingle<T>(int key)
{
// Get appropriate repository based on T1?
throw new System.NotImplementedException();
}
public IQueryable<T> GetAll<T>()
{
throw new System.NotImplementedException();
}
}
现在我面临的问题是——我如何确保当我调用:
_viewModelService.GetSingle<ProductVM>(id);
它自己(通过反射?)计算出它应该调用:
_unitOfWork.ProductRepository.Find(id)
在仓库内部吗?
哇,我觉得我解释得很糟糕!:)
TL;博士
我有一个UnitOfWork类: public class UnitOfWork : IDisposable
{
private readonly DbContext _context = new DbContext();
private BaseRepository<Order> _orderRepository;
private BaseRepository<Product> _productRepository;
private BaseRepository<ApplicationUser> _userRepository;
private bool _disposed;
public BaseRepository<Order> OrderRepository
{
get
{
if (_orderRepository == null)
{
_orderRepository = new BaseRepository<Order>(_context);
}
return _orderRepository;
}
}
public BaseRepository<Product> ProductRepository
{
get
{
if (_productRepository == null)
{
_productRepository = new BaseRepository<Product>(_context);
}
return _productRepository;
}
}
public BaseRepository<ApplicationUser> UserRepository
{
get
{
if (_userRepository == null)
{
_userRepository = new BaseRepository<ApplicationUser>(_context);
}
return _userRepository;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Save()
{
_context.SaveChanges();
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_context.Dispose();
}
}
_disposed = true;
}
}
现在我想创建一个通用包装器:
public class ViewModelService : IViewModelService
{
private readonly UnitOfWork _unitOfWork = new UnitOfWork();
public T GetSingle<T>(int key)
{
// Get appropriate repository based on T1?
throw new System.NotImplementedException();
}
}
我如何使用反射,以便当我请求GetSingle<ProductVM>(id)
时,包装器将其转换为对_unitOfWork.ProductRepository.Find(id);
的调用-因此包装器知道在UoW中调用正确的存储库。
。
方法之一是拥有一个通用的抽象类,并让具体的子类覆盖提供实际存储库的特定部分。这样,大部分代码都可以放在抽象类中,并且仍然可以精确地提供子类级别所需的内容。
// two generic types
// TDTO - view model type
// TDomain - domain type
public abstract class AbstractViewModelService<TDTO, TDomain> : IViewModelService
{
private UnitOfWork _uow { get; }
public AbstractViewModelService( UnitOfWork uow )
{
this._uow = uow;
}
public abstract IRepository<TDomain> Repository { get; }
public TDTO GetSingle<TDTO>(int key)
{
// Get appropriate repository based on T1?
// it is here ->
return Mapper.DynamicMap<TDTO>( this.Repository.Find( key ) );
}
}
public class UserViewModelService : AbstractViewModelService<UserDto, User>
{
public override IRepository<User> Repository
{
get
{
return this._uow.UserRepository;
}
}
...
}
public class AccountViewModelService : AbstractViewModelService<AccountDto, Account>
{
public override IRepository<Account> Repository
{
get
{
return this._uow.AccountRepository;
}
}
...
}
为什么不使用MEF?打破您的UOW,它将组成存储库-您还将受益于您将不会有重复的
。get
{
if (_productRepository == null)
{
_productRepository = new BaseRepository<Product>(_context);
}
return _productRepository;
}
为每个导出项添加元数据,然后在
public T GetSingle<T>(int key)
{
// Get appropriate repository based on T1?
throw new System.NotImplementedException();
}
你可以根据它暴露的元数据得到正确的插件。或者您可以将所有存储库添加到ServiceLoactor中,这样您就可以编写而不是
_unitOfWork.ProductRepository.Find(id);
ServiceLocator.Current.GetInstance<T>().find(id)