C#通用存储库-工作单元-线程安全

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

我目前正在编写一个依赖于数据库的应用程序,并使用Entity Framework(根据Nuget的版本6.1.1)

现在,我编写了一个存储库模式,如下所示:

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