6

我想从我的服务或存储库中解耦我的工作单元,以便在我希望添加新服务时不必触摸UoW代码。我该怎么做呢?从服务或回购解耦工作单元

_categoryService = _unitOfWork.Get<ICategoryService>(); 

所以不是

_unitOfWork.CategoryService.Add(category) 

我只能说;

_categoryService.Add(category); 
+0

您能否详细说明您的情况?在我看来,你正在谈论注入依赖(你的代码取决于ICategoryService,你想自动注入它),但是从你的问题中不清楚。 – 2013-03-03 09:38:54

+0

嗨!我有一个MVC4测试项目来研究UoW模式。我有一个控制器,一个引用存储库的服务类。但正如你所看到的,我在我的UoW中将这个CategoryService作为一个属性。然后我意识到,每当我为将来的事情创建一项新服务时,我都必须将此服务添加到我拥有的UoW类中。我正试图找到一种方法来获得一个Get 函数,该函数根据我传递给它的接口返回一个服务类型。我甚至不确定这是否正确。谢谢! – 2013-03-03 18:34:50

+0

你对UoW容器使用什么?你应该使用一些IoC的,检查这个页面的好的列表:http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx他们大多数有.Resolve ()方法,或类似的,你可以注册大部分的他们作为asp.net mvc中的默认依赖解析器,因此您只需将IService作为参数添加到您的控制器。这是你问什么? – 2013-03-03 18:48:55

回答

15

我想从我的服务或 库脱钩我的工作单位,这样我就不必每当我想 添加新的服务

触摸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); 
    } 

} 

就是这样!

现在,如果你想共享相同的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

对不起,我刚从一个很长的假期回来。我会试试这个。非常感谢! – 2013-04-12 14:52:07

+0

Max,让我问你一个问题。您将Repository方法定义为虚拟,因此您可以覆盖它们。如果你没有任何从Repository继承的类(也许我想要一个仓库以特定的方式删除),你会在哪里覆盖它们。我不喜欢扩展方法的想法,但它是一条出路。它会成为一种方式来处理从Repository继承的类(例如CustomerRepository),并覆盖一些方法并添加新的方法而不需要扩展方法? – snekkke 2013-12-13 17:14:52

+0

@snekkke感谢您的反馈。其实,你是对的。虚拟在这里毫无用处。定制事物的一种方法是将特定方法添加到“服务”中。添加这种方法可以完成以下工作:'内部Model.Customer GetByExternalIdAndChannelAsReadOnly(字符串externalCode,ChannelId通道) {0} {var} = Repository.Find(c = )信道).SingleOrDefault(); return cust; }' – MaxSC 2013-12-16 10:35:39