从服务或回购中分离工作单元

时间:2013-03-03 01:01:34

标签: c# model-view-controller interface repository-pattern unit-of-work

我正在尝试将我的工作单元与我的服务或存储库分离,以便每当我想添加新服务时,我都不必触摸UoW代码。我该怎么做?

_categoryService = _unitOfWork.Get<ICategoryService>();

所以而不是

_unitOfWork.CategoryService.Add(category)

我可以说;

_categoryService.Add(category);

1 个答案:

答案 0 :(得分:16)

  

我正在尝试将我的工作单元与我的服务分开   存储库,以便我不必在任何时候触摸UoW代码   添加新服务

嗯,这是一个好的开始! ; - )

我提出的解决方案不是唯一可行的解​​决方案,有几种很好的方法可以实现UoW(Google会帮助你)。但这应该会给你一个大局。

首先,创建2个接口:IUnitOfWork和IRepository

public interface IUnitOfWork : System.IDisposable
{
  IRepository<TEntity> GetRepository<TEntity>() where TEntity : class;
  void Save();
}

public interface IRepository<T> : IDisposable where T : class
{
  void Add(T entity);
  void Delete(T entity);
  void Update(T entity);
  T GetById(long Id);
  IEnumerable<T> All();
  IEnumerable<T> AllReadOnly();
  IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
} 

实现非常简单(为了便于阅读,我删除了所有注释,但不要忘记添加你的;-))

public class UnitOfWork<TContext> : IUnitOfWork where TContext : IDbContext, new()
{
  private readonly IDbContext _ctx;
  private Dictionary<Type, object> _repositories;
  private bool _disposed;

  public UnitOfWork()
  {
    _ctx            = new TContext();
    _repositories   = new Dictionary<Type, object>();
    _disposed       = false;
  }

  public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
  {
    if (_repositories.Keys.Contains(typeof(TEntity)))
      return _repositories[typeof(TEntity)] as IRepository<TEntity>;

    var repository = new Repository<TEntity>(_ctx);
    _repositories.Add(typeof(TEntity), repository);
    return repository;
  }

  public void Save()
  {
     try
     {
       _ctx.SaveChanges();
     }
     catch (DbUpdateConcurrencyException ex)
     {
       ex.Entries.First().Reload();
     }
  }

  …
}

public class Repository<T> : IRepository<T> where T : class
{
  private readonly IDbContext _context;
  private readonly IDbSet<T> _dbset;

  public Repository(IDbContext context)
  {
    _context = context;
    _dbset   = context.Set<T>();
  }

  public virtual void Add(T entity)
  {
    _dbset.Add(entity);
  }

  public virtual void Delete(T entity)
  {
    var entry = _context.Entry(entity);
    entry.State = EntityState.Deleted;
  }

  public virtual void Update(T entity)
  {
    var entry = _context.Entry(entity);
    _dbset.Attach(entity);
    entry.State = EntityState.Modified;
  }

  public virtual T GetById(long id)
  {
    return _dbset.Find(id);
  }

  public virtual IEnumerable<T> All()
  {
    return _dbset.ToList();
  }

  public virtual IEnumerable<T> AllReadOnly()
  {
    return _dbset.AsNoTracking().ToList();
  }

  public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
  {
    return _dbset.Where(predicate);
  }

}

如您所见,两种实现都使用IDbContext接口。此界面仅用于简单测试目的:

public interface IDbContext
{
  DbSet<T> Set<T>() where T : class;
  DbEntityEntry<T> Entry<T>(T entity) where T : class;
  int SaveChanges();
  void Dispose();
}

(如你所见,我正在使用EntityFramework Code First)

现在已经设置了整个管道,让我们看一下如何在服务中使用它。 我有一个基本服务,如下所示:

internal class Service<T> where T : class
{
  internal Service(Infrastructure.IUnitOfWork uow)
  {
    _repository = uow.GetRepository<T>();
  }

  protected Infrastructure.IRepository<T> Repository
  {
    get { return _repository; }
  }

  private readonly Infrastructure.IRepository<T> _repository;
}

我的所有服务都继承自这个基本服务。

internal class CustomerService : Service<Model.Customer>
{
  internal CustomerService(Infrastructure.IUnitOfWork uow) : base(uow)
  {   
  }

  internal void Add(Model.Customer customer)
  {
    Repository.Add(customer);
  }

  internal Model.Customer GetByID(int id)
  {
    return Repository.Find(c => c.CustomerId == id);
  }

}

就是这样!

现在,如果你想在一个Facade方法或其他地方共享同一个UoW到几个服务,它可能看起来像这样:

using (var uow = new UnitOfWork<CompanyContext>())
{
  var catService = new Services.CategoryService(uow);
  var custService = new Services.CustomerService(uow);

  var cat = new Model.Category { Name = catName };
  catService.Add(dep);

  custService.Add(new Model.Customer { Name = custName, Category = cat });

  uow.Save();
}

希望这有帮助!