Winforms DbContext Per Form

时间:2018-04-27 12:21:51

标签: c# winforms repository-pattern castle-windsor unit-of-work

我正在开发一个WindowsForms应用程序。我正在使用Repository,UoW,DI和EntityFramework。此类应用程序中的最佳实践是每个窗体使用一个DbContext窗体。

我的问题是,当我解析表单IoC时,表单会注入我的业务服务。这应该默认创建一个新的DbContext实例,这很好。当我从同一表单打开一个子表单时,即使有新的业务服务注入到这个子表单中,也会使用相同的DbContext实例。

即使我打开一个新表单,也会使用相同的DbContext实例,除非我发布已解析的表单。

不应该是每当我解析一个组件,并且该组件有多个依赖项时,就会创建所有新实例,特别是因为我使用的是Transient生活方式。

下面是我使用的代码的简短实现。我已经包含了重要的部分。

的UnitOfWork:

    public class UnitOfWork : IUnitOfWork
{
    private DbContextBase context = null;

    /// <summary>
    /// Constructer
    /// </summary>
    public UnitOfWork(DbContextBase context)
    {
        this.context = context;
    }

    /// <summary>
    /// Gets current context.
    /// </summary>
    public DbContextBase UoWContext
    {
        get { return context; }
    }
}

UnitOfWorkManager:

    public class UnitOfWorkManager
{
    private static IUnitOfWork _unitOfWork { set; get; }

    private UnitOfWorkManager()
    {
    }

    public static IUnitOfWork Current
    {
        get
        {
            if (_unitOfWork != null)
                return _unitOfWork;
            else
            {
                _unitOfWork = Create();
                return _unitOfWork;
            }
        }
        set
        {
            _unitOfWork = value;
        }
    }

    private static IUnitOfWork Create()
    {
        return IoCManager.IoC.Resolve<IUnitOfWork>();
    }
}

存储库:

    public class Repository<TEntity, TKey> : IRepository<TEntity, TKey>
    where TEntity : class
{
    public Repository()
    {
    }

    private DbContextBase Context
    {
        get
        {
            return UnitOfWorkManager.Current.UoWContext;
        }
    }

    private DbSet<TEntity> DbSet
    {
        get
        {
            return Context.Set<TEntity>();
        }
    }
}

商业服务:

{
public class BusinessService<TEntity, TKey> : IBusinessService<TEntity, TKey>
    where TEntity : IEntity
{
    protected IRepository<TEntity, TKey> _repository;

    public BusinessService(IRepository<TEntity, TKey> repository)
    {
        _repository = repository;
    }
}

使用Castle-Windsor进行DI注册:

IoCManager.IoC.Register<DbContextBase, PMDbContext>(IoCLifeStyle.Transient);
IoCManager.IoC.Register<IEFUnitOfWork, EFUnitOfWork>(IoCLifeStyle.Transient);
IoCManager.IoC.Register<IRepository>(typeof(IRepository).Assembly, IoCLifeStyle.Transient);
IoCManager.IoC.Register<BusinessServiceInterceptor>(IoCLifeStyle.Singelton);
IoCManager.IoC.Register<IBusinessService, BusinessServiceInterceptor>(typeof(IBusinessService).Assembly, IoCLifeStyle.Transient, typeof(BusinessServiceInterceptor));
//Forms
IoCManager.IoC.Register<frm_Main>(PM.Common.Enums.IoCLifeStyle.Transient);
IoCManager.IoC.Register<frm_Calander>(PM.Common.Enums.IoCLifeStyle.Transient);
IoCManager.IoC.Register<frm_Calanders>(PM.Common.Enums.IoCLifeStyle.Transient);

1 个答案:

答案 0 :(得分:0)

你必须稍微改变你的设计:

public class Repository<TEntity, TKey> : IRepository<TEntity, TKey> where TEntity : class
{
    private readonly IUnitOfWork _unitOfWork;

    public Repository(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    private DbContextBase Context
    {
        get
        {
            return _unitOfWork.UoWContext;
        }
    }

    private DbSet<TEntity> DbSet
    {
        get
        {
            return Context.Set<TEntity>();
        }
    }
}

然后每当要求新表格时

  • 注入新服务
  • 获取新存储库
  • 获得一个新的 unitOfWork
  • 获取新的dbContext

在同一表单中对服务的每次调用都将导致调用相同的底层服务 - &gt;存储库 - &gt; unitOfWork - &gt;上下文。

如果您在表单中有更多服务,应该共享相同的uow实例:

Container.Register(Component.For<IUnitOfWork>()
    .ImplementedBy<UnitOfWork>()
    .LifestyleBoundToNearest<frmBase>());

https://github.com/castleproject/Windsor/blob/master/docs/lifestyles.md

然后uow及其上下文仅限于最近的形式。