7

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

_categoryService = _unitOfWork.Get<ICategoryService>();

所以而不是

_unitOfWork.CategoryService.Add(category)

我只能说;

_categoryService.Add(category);
4

1 回答 1

17

我正在尝试将我的工作单元与我的服务或存储库分离,以便在我希望添加新服务时不必接触 UoW 代码

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

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

首先,创建 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);
  }

}

就是这样!

现在,如果您想以外观方法或其他方式将相同的 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();
}

希望这可以帮助!

于 2013-03-20T15:12:31.007 回答