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

how to implement UOW in C# with EF6

我正在尝试在我的应用程序中使用存储库模式实施 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
}

客户UOW

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


}

How do I implement my CustomerUOW so that Customer & CustomerContact repository share the same DbContext & goes in one transaction??

注意:每个存储库在其各自的 class 中都有一个 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;
    }
}

谢谢

方法是在您的 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

作为最后的手段,您始终可以回退到手动创建工厂或切换 IoC/DI 开箱即用或至少原生支持 Func<[TIn1, TIn2, ...], T> 的容器。