简体   繁体   English

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

[英]how to implement UOW in C# with EF6

I am trying to implement UOW with repository pattern in my application. 我正在尝试在应用程序中使用存储库模式实现UOW。

While the independent repository is in place, but while multiple repositories in one transaction (UOW) is driving me crazy. 尽管有独立的存储库,但是一次交易(UOW)中的多个存储库却让我发疯。

EF Relation One Customer - Many CustomerContacts

IUnitOfWork IUnitOfWork

 public interface IUnitOfWork
    : IDisposable
{
    void InitTransaction();

    void Rollback();

    void CommitTransaction();

}

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


}

How do I implement my CustomerUOW so that Customer & CustomerContact repository share the same DbContext & goes in one transaction?? 如何实现我的CustomerUOW以便CustomerCustomerContact存储库共享相同的DbContext并进行一次事务?

Note: Each repository has an implementation of CRUD in their separate class. 注意:每个存储库在其单独的类中都有一个CRUD实现。 like 喜欢

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

Thanks 谢谢

On way would be to provide a Func<FoodieTenantContext, IRepository<CustomerContactRepository>> in your CustomerUow 即将在您的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);
    }
}

Another option would be to create a RepositoryFactory, but this would mean you would have to expose a Context property from IRepository<T> 另一个选择是创建一个RepositoryFactory,但这意味着您将必须从IRepository<T>公开一个Context属性。

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

}

Another solution could be (my least favourite) would be to expose methods in a RepositoryFactory for each type of IRepository<T> 另一个解决方案(我最不喜欢)是针对每种IRepository<T>类型在RepositoryFactory公开方法。

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

Registering Func in Castle.Windsor 在Castle.Windsor中注册Func

As per comment, to register Func<T> in Castle.Windsor you can try something like the following which is a modified version of Anton's answer to Func injecting with Windsor container question. 根据评论,要在Castle.Windsor中注册Func<T> ,您可以尝试以下类似方法,它是Anton对Func注入温莎容器问题的答案的修改版本 . (I am not able to test this right now) (我现在无法对此进行测试)

Container.Register(

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

Otherwise you could try playing around with AsFactory() . 否则,您可以尝试使用AsFactory() For more info read Windsor documentation 有关更多信息,请阅读Windsor文档

And as a last resort, you can always fallback to manually creating a factory or switching IoC/DI containers that support Func<[TIn1, TIn2, ...], T> out of the box, or at least natively. 而且,作为最后的手段,您始终可以退回到手动创建工厂或切换支持Func<[TIn1, TIn2, ...], T>或至少本机支持的IoC / DI容器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM