6

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

_categoryService = _unitOfWork.Get<ICategoryService>(); 

ので、代わりの

_unitOfWork.CategoryService.Add(category) 

私は言うことができます。

_categoryService.Add(category); 
+0

あなたのシナリオについてもっと詳しく説明できますか?依存関係の注入(あなたのコードはICategoryServiceに依存し、自動的に注入したいと思っています)について話しているようですが、あなたの質問からは明らかではありません。 –

+0

こんにちは! UoWパターンを学習するためのMVC4テストプロジェクトがあります。私はコントローラ、リポジトリを参照するサービスクラスを持っています。しかし、あなたが見ることができるように、私はこのCategoryServiceを私のUoWにプロパティとして持っています。それから私は将来、何かのために新しいサービスを作るたびに、私が持っているUoWクラスにこのサービスを追加しなければならないことに気付きました。私はそれに渡されたインターフェイスに基づいてサービスタイプを返すGet 関数を持つ方法を見つけることを試みています。それが正しいかどうかは確かではありません。ありがとう! –

+0

UoWコンテナには何を使用していますか?あなたはいくつかのIoCを使うべきです、このページで良いリストをチェックしてください:http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspxそれらのほとんどは.Resolve ()メソッドを持っています。それらをasp.net mvcのデフォルト依存リゾルバとして使用するので、コントローラにパラメータとしてIServiceを追加するだけです。あなたは何を求めているのですか? –

答えて

15

私は新しいサービス

を追加し を希望するたびUOWコードに触れていないように私のサービスや リポジトリから作業の私のユニットを分離しようとしています

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

私が提示している解決策は、唯一可能な解決策ではありません.UoWを実装するいくつかの良い方法があります(Googleがお手伝いします)。しかし、これはあなたに大きなイメージを与えるはずです。 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); 
    } 

} 

まず、2つのインターフェースを作成

ご覧のとおり、どちらの実装も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(); 
} 

ホープ、このことができます!

+0

申し訳ありません、私はちょうど非常に長い休暇から戻ってきました。私はこれを試してみる。どうもありがとう! –

+0

最大、あなたに質問をさせてください。リポジトリメソッドを仮想として定義して、それらをオーバーライドすることができます。リポジトリから継承するクラスがない場合は、どこから上書きしますか(リポジトリから特定の方法で削除したい場合があります)。私は拡張メソッドの考え方が嫌いですが、それは道のりです。 Repository(例えばCustomerRepository)を継承し、いくつかのメソッドをオーバーライドし、拡張メソッドを必要とせずに新しいメソッドを追加するクラスで作業する方法でしょうか? – snekkke

+0

@snekkkeご意見ありがとうございます。実際は、そうです。バーチャルはここではまったく役に立たない。物をカスタマイズする1つの方法は、あなたの 'サービス'に特定のメソッドを追加することです。この種のメソッドを追加すると、次のようなことができます:内部Model.Customer GetByExternalIdAndChannelAsReadOnly(文字列externalCode、ChannelIdチャネル) { var cust = Repository.Find(c => c.ExternalCode == externalCode && c.ChannelId ==(byte )チャネル).SingleOrDefault(); return cust; } ' – MaxSC

関連する問題