7

新しいサービスを追加したいときはいつでも UoW コードに触れる必要がないように、作業単位をサービスまたはリポジトリから分離しようとしています。どうすればいいですか?

_categoryService = _unitOfWork.Get<ICategoryService>();

だから代わりに

_unitOfWork.CategoryService.Add(category)

私はただ言うことができます;

_categoryService.Add(category);
4

1 に答える 1

17

新しいサービスを追加するたびにUoWコードに触れる必要がないように、作業単位をサービスまたはリポジトリから切り離そうとしています。

さて、それは良いスタートです!;-)

私が提示している解決策は唯一の可能な解決策ではありません。UoWを実装するためのいくつかの良い方法があります(Googleがお手伝いします)。しかし、これはあなたに全体像を与えるはずです。

まず、IUnitOfWorkとIRepositoryの2つのインターフェイスを作成します

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コードを最初に使用しています)

配管全体がセットアップされたので、これをサービスでどのように使用できるかを見てみましょう。私は次のような基本サービスを持っています:

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 に答える