C#通用存储库-工作单元-线程安全
我目前正在编写一个依赖于数据库的应用程序,并使用Entity Framework(根据Nuget的版本6.1.1) 现在,我编写了一个存储库模式,如下所示:C#通用存储库-工作单元-线程安全,c#,multithreading,entity-framework,C#,Multithreading,Entity Framework,我目前正在编写一个依赖于数据库的应用程序,并使用Entity Framework(根据Nuget的版本6.1.1) 现在,我编写了一个存储库模式,如下所示: public class RepositoryBase<TEntity> where TEntity : class { #region Constructors protected RepositoryBase(IDbContext context, IUnitOfWork unitOfWork) {
public class RepositoryBase<TEntity> where TEntity : class
{
#region Constructors
protected RepositoryBase(IDbContext context, IUnitOfWork unitOfWork)
{
Context = context;
DbSet = Context.Set<TEntity>();
UnitOfWork = unitOfWork;
}
#endregion
#region Properties
protected IDbSet<TEntity> DbSet;
protected readonly IDbContext Context;
protected readonly IUnitOfWork UnitOfWork;
#endregion
#region Methods
protected TEntity Get(Expression<Func<TEntity, bool>> filter)
{
DbSet.ThrowIfNull("DbSet");
IQueryable<TEntity> query = DbSet;
return !query.Any() ? null : !query.Where(filter).Any() ? null : query.First(filter);
}
protected TEntity Get(Expression<Func<TEntity, bool>> filter, string[] includeProperties)
{
DbSet.ThrowIfNull("DbSet");
IQueryable<TEntity> query = DbSet;
includeProperties.Each(x => query = query.Include(x));
return !query.Any() ? null : !query.Where(filter).Any() ? null : query.First(filter);
}
protected virtual IQueryable<TEntity> GetAll()
{
DbSet.ThrowIfNull("DbSet");
IQueryable<TEntity> query = DbSet;
return query.AsQueryable();
}
protected IQueryable<TEntity> GetAll(string[] includeProperties)
{
DbSet.ThrowIfNull("DbSet");
IQueryable<TEntity> query = DbSet;
includeProperties.Each(x => query = query.Include(x));
return query.AsQueryable();
}
protected IQueryable<TEntity> GetAll(Expression<Func<TEntity, bool>> filter)
{
DbSet.ThrowIfNull("DbSet");
IQueryable<TEntity> query = DbSet;
query = DbSet.Where(filter);
return query;
}
protected IQueryable<TEntity> GetAll(Expression<Func<TEntity, bool>> filter, string[] includeProperties)
{
DbSet.ThrowIfNull("DbSet");
IQueryable<TEntity> query = DbSet;
query = DbSet.Where(filter);
includeProperties.Each(x => query = query.Include(x));
return query;
}
#endregion
}
container.RegisterType<IDbContext, OxygenDataContext>(new PerRequestLifetimeManager());
protected virtual void Dispose(bool disposing)
{
if (disposing) { Context = null; }
}
public void Dispose()
{
Dispose(true);
}
我的类型注册在此处完成:
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<IDbContext, OxygenDataContext>();
container.RegisterType<IUnitOfWork, UnitOfWork>(new PerRequestLifetimeManager());
}
但是,它不起作用。我在这里有点迷路了,所以如果有人知道解决方案:-)
更新6
根据一些帖子,我需要提供一些关于如何实例化存储库的信息。
下面是解释:
我使用的UnitOfWork包含所有存储库:
/// <summary>
/// Creates a new instance of the <see cref="IUnitOfWork"/>.
/// </summary>
/// <param name="context">The <see cref="IDbContext"/> in which the entities are available.</param>
public UnitOfWork(IDbContext context)
: base(context)
{
versioningRepository = new Repository<Versioning>(context, this);
settingRepository = new Repository<Setting>(context, this);
siteRepository = new VersionedRepository<Site, int>(context, this);
pageRepository = new VersionedRepository<Page, int>(context, this);
layoutRepository = new VersionedRepository<Layout, int>(context, this);
assemblyRepository = new VersionedRepository<Assembly, int>(context, this);
logRepository = new Repository<Log>(context, this);
}
//
///创建的新实例。
///
///实体可用的位置。
公共工作单元(IDbContext上下文)
:基本(上下文)
{
versioningRepository=新存储库(上下文,此);
settingRepository=新存储库(上下文,此);
siteRepository=new VersionedRepository(上下文,this);
pageRepository=new VersionedRepository(上下文,this);
layoutRepository=new VersionedRepository(上下文,this);
assemblyRepository=new VersionedRepository(上下文,this);
logRepository=新存储库(上下文,此);
}
我还尝试将代码更改为以下内容,但这也不起作用:
/// <summary>
/// Creates a new instance of the <see cref="IUnitOfWork"/>.
/// </summary>
/// <param name="context">The <see cref="IDbContext"/> in which the entities are available.</param>
public UnitOfWork(IDbContext context)
: base(context)
{
versioningRepository = new Repository<Versioning>(context, this);
settingRepository = new Repository<Setting>(new OxygenDataContext(), this);
siteRepository = new VersionedRepository<Site, int>(new OxygenDataContext(), this);
pageRepository = new VersionedRepository<Page, int>(new OxygenDataContext(), this);
layoutRepository = new VersionedRepository<Layout, int>(new OxygenDataContext(), this);
assemblyRepository = new VersionedRepository<Assembly, int>(new OxygenDataContext(), this);
logRepository = new Repository<Log>(new OxygenDataContext(), this);
}
//
///创建的新实例。
///
///实体可用的位置。
公共工作单元(IDbContext上下文)
:基本(上下文)
{
versioningRepository=新存储库(上下文,此);
settingRepository=新存储库(new OxygenDataContext(),this);
siteRepository=new VersionedRepository(new OxygenDataContext(),this);
pageRepository=new VersionedRepository(new OxygenDataContext(),this);
layoutRepository=new VersionedRepository(new OxygenDataContext(),this);
assemblyRepository=new VersionedRepository(new OxygenDataContext(),this);
logRepository=new Repository(new OxygenDataContext(),this);
}
我仍然收到错误消息:“基础提供程序在打开时失败”,内部异常为“连接未关闭。连接的当前状态为连接”
您可以看到UnitOfWork的构造函数确实采用IDbContext实例,并且所有存储库都是使用同一实例构建的
我使用的是Unity,IDbContext的注册采用以下代码:
container.RegisterType<IDbContext, OxygenDataContext>(new PerResolveLifetimeManager());
container.RegisterType<IDbContext, OxygenDataContext>();
container.RegisterType();
在我的Unity配置中,我还注册了IUnitOfWork接口:
container.RegisterType<IUnitOfWork, UnitOfWork>(new PerRequestLifetimeManager());
container.RegisterType(新的PerRequestLifetimeManager());
我确实感觉到错误在Unity注册或UnitOfWork中的某个地方,但我似乎没有找到它。如果我没有弄错您的消息,那么您在线程之间共享相同的DbContext。这不是DbContext的用途。以这种方式共享数据非常困难 我不喜欢以“但是你为什么需要它”的形式给出答案,但这篇文章看起来就是这样 我建议您重新设计解决方案,并保持DbContext对象的短期性—执行操作并处置DbContext。执行一个工作单元,提交/回滚并使用存储库完成。不要忘记DbContext将跟踪它获取的所有对象。您可能不希望跟踪对象在内存中的寿命比使用它们的事务长
让数据库成为共享来自多个线程的数据的点。这里可能没有完全处理上下文:
protected virtual void Dispose(bool disposing)
{
if (disposing) { Context = null; }
}
public void Dispose()
{
Dispose(true);
}
我的理解是,当您创建dbContext的抽象(比如UoW)时,您希望明确地调用垃圾收集器,以确保您已经清理了未使用的资源。此外,还需要处理dbContext,而不是将其设置为null
例如:
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
context.Dispose(); // <-- dispose
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private bool disposed=false;
受保护的虚拟void Dispose(bool disposing)
{
如果(!this.disposed)
{
如果(处置)
context.Dispose();//问题在于如何注册IDbContext实例。
DbContext不是线程安全的,所以您应该每个请求/线程解析一次它(与您对Repository和UnitOfWork的解析相同),所以将注册代码更改为:
container.RegisterType<IDbContext, OxygenDataContext>(new PerRequestLifetimeManager());
container.RegisterType(新的PerRequestLifetimeManager());
什么是内部异常?您的图像模糊,很难读取内部异常。实际上,图像有点模糊。内部异常是:“连接未关闭。连接的当前状态为连接。”你不是偶然在线程之间共享同一个存储库吗?因为你对DbContext注册的操作很好。你是如何解决存储库本身的问题的?对不起,我不太理解你的问题,我发布的更新不是很清楚吗?只需显示创建和使用存储库的代码。我相信这就是问题所在问题是。谢谢你的回答。我知道共享上下文是个坏主意,但我坐在Microsoft Unity中间,这似乎对我不利:)我明白。我使用的一种方法是创建存储库,其中T是IDbContext。然后存储库实例化T。这样,IDbContext的生存期等于IDbContext的生存期存储库对象。我用更新2更新了我的问题,这样Unity现在可以在“PerRequestLifetimeManager”上解析我的DbContext,但它似乎不起作用。我确实需要这种东西来简化单元测试…我只是不明白为什么Unity不能管理这类事情…当我使用您的方法时,存储库w在这里,T:IDbContext,Unity应该如何解析IDbContext接口,以及PerRequest,或者不需要,或者可能与其他东西一起解析?这里没有更多的Unity。您将实例化存储库,以便存储库和数据上下文的生命周期变得相同。IDbContext不再通过构造函数接收。在相关的e、 你可以
container.RegisterType<IUnitOfWork, UnitOfWork>(new PerRequestLifetimeManager());
protected virtual void Dispose(bool disposing)
{
if (disposing) { Context = null; }
}
public void Dispose()
{
Dispose(true);
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
context.Dispose(); // <-- dispose
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
container.RegisterType<IDbContext, OxygenDataContext>(new PerRequestLifetimeManager());