将工作单元与服务或存储库分离 [英] Decouple unit of work from services or repo

查看:19
本文介绍了将工作单元与服务或存储库分离的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to decouple my unit of work from my services or repository so that I wont have to touch the UoW code whenever I wish to add a new service. How do I do this?

_categoryService = _unitOfWork.Get<ICategoryService>();

所以而不是

_unitOfWork.CategoryService.Add(category)

我只能说;

_categoryService.Add(category);

推荐答案

我正在尝试将我的工作单元与我的服务分离,或者存储库,这样我就不必随时接触 UoW 代码添加新服务

I am trying to decouple my unit of work from my services or repository so that I won’t have to touch the UoW code whenever I wish to add a new service

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

Well, that’s a good start! ;-)

我提出的解决方案不是唯一可行的解​​决方案,有几种实现 UoW 的好方法(Google 会帮助您).但这应该可以让您了解全局.

The solution I am presenting is not the one and only possible solution, there are several good ways to implement UoW (Google will help you out). But this should give you the big picture.

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

First, create 2 interfaces: IUnitOfWork and 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);
} 

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

The implementations are quite straightforward (I removed all my comments for readability purpose, but do not forget to add yours ;-) )

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 接口.此界面仅用于简单测试目的:

As you can see, both implementations make use of IDbContext interface. This interface is just for easy testing purpose:

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)

(As you can see, I’m using EntityFramework Code First)

现在整个管道都设置好了,让我们看看如何在服务中使用它.我有一个看起来像这样的基本服务:

Now that the whole plumbing is set up, let’s have a look at how this could be used in a service. I have a base service that looks like this:

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;
}

我所有的服务都继承自这个基础服务.

And all my services inherit from this base service.

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 共享给多个服务,它可能看起来像这样:

Now, if you want to share the same UoW to several services, in a facade method or somewhere else, it could just look like this:

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();
}

希望这有帮助!

这篇关于将工作单元与服务或存储库分离的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆