Design patterns UnitOfWork,存储库数据库连接问题
我使用Design patterns UnitOfWork,存储库数据库连接问题,design-patterns,asp.net-web-api2,repository-pattern,unit-of-work,Design Patterns,Asp.net Web Api2,Repository Pattern,Unit Of Work,我使用Unity进行依赖注入。我按照前面提到的方向实现了通用存储库IRepository和IUnitOfWork 现在,当我使用构造函数注入访问服务层中的存储库和UnitOfWork时,它会在数据库中添加数据,但不会关闭与数据库的连接 UnitOfWork实现了IDisposable,但从未调用过它,因为我无法使用模式实现,因为我知道存储库和UnitOfWork也被其他函数共享 container.RegisterType<IRMContext, RMContext>(new Per
Unity
进行依赖注入。我按照前面提到的方向实现了通用存储库IRepository
和IUnitOfWork
现在,当我使用构造函数注入访问服务层中的存储库和UnitOfWork时,它会在数据库中添加数据,但不会关闭与数据库的连接
UnitOfWork实现了IDisposable
,但从未调用过它,因为我无法使用模式实现,因为我知道存储库和UnitOfWork也被其他函数共享
container.RegisterType<IRMContext, RMContext>(new PerResolveLifetimeManager());
container.RegisterType<IUnitOfWork, UnitOfWork>(new PerResolveLifetimeManager());
container.RegisterType(新的PerResolveLifetimeManager());
RegisterType(新的PerResolveLifetimeManager());
因此,对于来自fiddler的每个请求,它都会创建一个到数据库的新连接,并且永远不会关闭,最终会达到100个或更多,然后开始失败强>
我在dotnetfiddle中添加了代码-
根据我的研究进一步更新。如果您查看代码,则其中有IUnitOfWork
实现具有BeginTransaction
方法。如果我不在服务层中使用它,那么一切都可以正常工作。仅维护1个数据库连接。但是,如果使用了它,与该事务相关联的连接将永远不会关闭,并且会不断增加。在Unity体系结构中,负责处理所创建对象的对象是LifetimeManager及其实现。在您使用的示例中,是PerResolveLifetimeManager
如果你看到
,您将看到并非每个LifetimeManager都会处理其对象。例如:
TransientLifetimeManager:不调用Dispose
ContainerControlled LifetimeManager:当容器被释放时,它调用对象的Dispose方法。
HierarchyCallifeTimeManager:当容器被释放时,它调用对象的Dispose方法。
PerResolveLifetimeManager:不调用Dispose。
PerThreadLifetimeManager:不调用Dispose。
外部控制的LifetimeManager:不调用Dispose
我们可以使用以下代码对此进行测试:
[TestMethod]
public void PerResolveLifetimeManagerDoesNotCallDispose()
{
var container = new UnityContainer();
container.RegisterType<IUnitOfWork, UnitOfWork>(new PerResolveLifetimeManager());
var uow = (UnitOfWork)container.Resolve<IUnitOfWork>();
Assert.IsFalse(uow.Disposed);
container.Dispose();
Assert.IsFalse(uow.Disposed);
}
public interface IUnitOfWork : IDisposable
{
}
public class UnitOfWork : IUnitOfWork
{
public bool Disposed { get; set; }
public void Dispose()
{
Disposed = true;
}
}
一个可能的测试是:
[TestMethod]
public void WithChild()
{
var container = new UnityContainer();
container.RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager());
for (int i = 0; i < 10; ++i)
{
var child = container.CreateChildContainer();
var uow = (UnitOfWork)child.Resolve<IUnitOfWork>();
Assert.IsFalse(uow.Disposed);
child.Dispose();
Assert.IsTrue(uow.Disposed);
}
}
此解决方案包含一个技巧:如果您忘记调用子容器上的dispose,将发生两件事:
1-永远不会调用对象的处置方法,请参见下面的测试
[TestMethod]
public void DoNotForgetToCallTheDispose()
{
var container = new UnityContainer();
container.RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager());
List<UnitOfWork> objects = new List<UnitOfWork>();
for (int i = 0; i < 10; ++i)
{
var child = container.CreateChildContainer();
var uow = (UnitOfWork)child.Resolve<IUnitOfWork>();
objects.Add(uow);
Assert.IsFalse(uow.Disposed);
}
Assert.IsTrue(objects.All(x => x.Disposed)); // Will throw!
}
使用一次性的暂时性工作单位。有一个工作单元工厂,在需要时为您提供一个工作单元,以便在不影响其他模块的情况下对其进行处理。@Nkosi,您能解释更多吗?正如我提到的,我已经为unitOfWork实现了一次性,但由于IOC的原因,它从未被调用……我正在使用PerResolveLifetimeManager来管理DBConect和IUnitOfWork。它对请求使用相同的上下文,但一旦请求被服务,它就必须被销毁,对吗?但它没有,对于另一个请求,它会打开一个新的连接,并继续遵循相同的策略。@Nkosi您好,我根据HttpRequest生命周期管理器实现了此功能以解决此问题,但它仍然没有关闭这些连接。这里是链接-这是非常详细和准确的解释,任何人都可以给出。非常感谢。Frederico Lins,如果我的服务是PerResolveLifetimeManager,而IUnitOfWork&DBConext是PerreRequestLifetimeManager,会发生什么情况?(我没有在Request_End中明确删除或调用dispose)如果您的服务是PerResolve,并且您从未调用dispose,那么它们永远不会被直接处理。如果您的IUnitOfWork和DBContext是PerRequest,并且您配置了UnityPerRequestHttpModule,则会自动释放它们,
+ Root
-- Child 1
-- Uow1
-- Svc1
-- Child 2
-- Uow1
-- Svc2
[TestMethod]
public void WithChild()
{
var container = new UnityContainer();
container.RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager());
for (int i = 0; i < 10; ++i)
{
var child = container.CreateChildContainer();
var uow = (UnitOfWork)child.Resolve<IUnitOfWork>();
Assert.IsFalse(uow.Disposed);
child.Dispose();
Assert.IsTrue(uow.Disposed);
}
}
public class UnityDependencyResolver : UnityDependencyScope, IDependencyResolver, IDependencyScope, IDisposable
{
public UnityDependencyResolver(IUnityContainer container) : base(container)
{
}
public IDependencyScope BeginScope()
{
return new UnityDependencyScope(base.Container.CreateChildContainer());
}
}
[TestMethod]
public void DoNotForgetToCallTheDispose()
{
var container = new UnityContainer();
container.RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager());
List<UnitOfWork> objects = new List<UnitOfWork>();
for (int i = 0; i < 10; ++i)
{
var child = container.CreateChildContainer();
var uow = (UnitOfWork)child.Resolve<IUnitOfWork>();
objects.Add(uow);
Assert.IsFalse(uow.Disposed);
}
Assert.IsTrue(objects.All(x => x.Disposed)); // Will throw!
}
private UnityContainer(UnityContainer parent)
{
this.parent = parent;
if (parent != null)
{
parent.lifetimeContainer.Add(this);
}
...
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
...
if (this.parent != null && this.parent.lifetimeContainer != null)
{
this.parent.lifetimeContainer.Remove(this);
}
...
}
}