如何使用EF6在C#中实现UOW

时间:2018-07-22 09:55:52

标签: c# entity-framework-6 repository-pattern unit-of-work

我正在尝试在应用程序中使用存储库模式实现UOW。

虽然有独立的存储库,但是一次交易(UOW)中有多个存储库却令我发疯。

EF Relation One Customer - Many CustomerContacts

IUnitOfWork

 public interface IUnitOfWork
    : IDisposable
{
    void InitTransaction();

    void Rollback();

    void CommitTransaction();

}

BaseUOW

 public class UnitOfWork :
    IUnitOfWork
{

    protected DbContextTransaction _transaction;


    #region IUnitOfWork

     public void CommitTransaction()
    {
        _transaction.UnderlyingTransaction.Commit();
    }

    public void Rollback()
    {
        _transaction.UnderlyingTransaction.Rollback();
    }
    #endregion IUnitOfWork
}

CustomerUOW

 public class CustomerUOW
    : UnitOfWork
{
    private IRepository<CustomerRepository> _customerRepository;
    private IRepository<CustomerContactRepository> _customerContactRepository;

    public BranchUOW(IRepository<CustomerRepository> customerRepository, 
        IRepository<CustomerContactRepository> customerContactRepository)
    {
        _customerRepository= customerRepository;
        _customerContactRepository= customerContactRepository;
    }
    public override void InitTransaction()
    {
        _transaction.Commit();
    }


}
  

如何实现CustomerUOW以便Customer和   CustomerContact存储库共享相同的DbContext并合而为一   交易?

注意:每个存储库在其单独的类中都有一个CRUD实现。喜欢

 public class EntityRepository<C, T>
   : BaseRepository<FoodieTenantContext, T>
    where T : class
    where C : CustomerContext
{
    private DbSet<T> _dataSet
    {
        get
        {
            return _ctx.Set<T>();
        }
    }

    public EntityRepository(FoodieTenantContext ctx)
        : base(ctx)
    {
    }

    public override void Add(T entity)
    {
        _dataSet.Add(entity);
    }

    public override void Delete(T entity)
    {
        throw new NotImplementedException();
    }

    public override IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
    {
        return _dataSet.Where(predicate).ToList<T>();
    }

    public override IEnumerable<T> GetAll()
    {
        return _dataSet.ToList<T>();
    }

    public override IQueryable<T> GetQuery()
    {
        return _dataSet;
    }

    public override int Save()
    {
        return _ctx.SaveChanges();
    }

    public override T Single(Expression<Func<T, bool>> predicate)
    {
        return _dataSet.Where(predicate).SingleOrDefault();
    }

    public override void Update(T entity)
    {
        _dataSet.Attach(entity);
        _ctx.Entry<T>(entity).State = EntityState.Modified;
    }
}

谢谢

1 个答案:

答案 0 :(得分:1)

一种方式是在CustomerUow中提供一个Func<FoodieTenantContext, IRepository<CustomerContactRepository>>

public abstract class UnitOfWork : IUnitOfWork
{
    public UnitOfWork(FoodieTenantContext context)
    {
        this.Context = context;
    }

    // ... rest of the class
}

// usage could be like the following

public class CustomerUOW : UnitOfWork
{
    public CustomerService(Func<FoodieTenantContext, IRepository<CustomerRepository>> customerRepo
        , Func<FoodieTenantContext, IRepository<CustomerContactRepository>> contactRepo
        , FoodieTenantContext context) 
        : (context)
    {        
        _customerRepo = customerRepo(context);
        _contactRepo = contactRepo(context);
    }
}

另一种选择是创建一个RepositoryFactory,但这意味着您将不得不从Context公开一个IRepository<T>属性

public class RepositoryFactory
{
    IServiceProvider _ioc; // This would be your IoC/DI Container

    public RepositoryFactory(IServiceProvider ioc)
    {
        _ioc = ioc;
    }

    // Resolve T passing in the provided `FoodieTenantContext` into the constructor
    public IRepository<T> CreateRepository<T>(FoodieTenantContext context) =>
        _ioc.Resolve<T>(context); 

}

(我最不喜欢的)另一种解决方案是针对每种RepositoryFactory类型在IRepository<T>中公开方法

public class RepositoryFactory
{
    public IRepository CreateCustomerContactRepository(FoodieTenantContext context) => 
        return new CustomerContactRepository(context);
}

在Castle.Windsor中注册Func

根据评论,要在Castle.Windsor中注册Func<T>,您可以尝试以下类似方法,它是Anton's answer to Func injecting with Windsor container question.的修改版本。 (我现在无法对此进行测试)

Container.Register(

  Component.For<Func<FoodieTenantContext, IRepository<CustomerRepository>>>()
           .Instance((FoodieTenantContext context) => Container.Resolve<IRepository<CustomerRepository>>(new {context = context}))
)

否则,您可以尝试使用AsFactory()。有关更多信息,read Windsor documentation

作为最后的选择,您始终可以退后至手动创建工厂或切换支持Func<[TIn1, TIn2, ...], T>或至少本机支持的IoC / DI容器。