【发布时间】:2014-09-26 23:35:34
【问题描述】:
我目前正在编写一个依赖于数据库的应用程序,并且我正在使用实体框架(根据 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
}
我确实有其他类继承自此存储库,但我暂时将它们排除在范围之外。
现在,当我在存储库上执行 Get 操作时,我检索了数据,但是当我执行 2 个调用时(我只打开 2 个具有相同 url 的浏览器窗口并执行它们),然后出现以下错误是否弹出:
“System.Data.Entity.Core.EntityException”类型的异常 发生在 EntityFramework.SqlServer.dll 中但未在用户中处理 代码
附加信息:底层提供程序在打开时失败。
这里有一张小图,可以提供尽可能详细的信息:
现在,我知道实体框架 DbContext 默认情况下不是线程安全的,所以我知道我应该做一些事情来使其成为线程安全的,但我只是不知道该怎么做。
任何人都可以就如何实现这一目标向我提供任何指导吗? 另外,我对 IDisposeable 没有太多经验,所以如果您建议在某个地方实现它,您应该非常好心地向我提供一些有关如何实现它的信息。
值得一提的是,我正在使用 Unity 来管理我的对象,您可以在此处找到其中的配置:
DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
我的类型的注册在这里完成:
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<IDbContext, OxygenDataContext>();
container.RegisterType<IUnitOfWork, UnitOfWork>(new PerRequestLifetimeManager());
}
“OxygenDataContext”类是我对“DbContext”和“IDbContext”的实现。 该代码可以在下面找到(一个片段,我没有发布我的所有元素):
public class OxygenDataContext : DbContext, IDbContext
{
#region Constructors
public OxygenDataContext()
: base("Oxygen")
{
Configuration.ProxyCreationEnabled = false;
}
#endregion
#region IDbContext Members
public IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}
public void SaveChanges()
{
base.SaveChanges();
}
#endregion
}
更新
据我说,是 Unity 导致了这种行为,因为我正在使用:
container.RegisterType<IDbContext, OxygenDataContext>();
这意味着不会在每个请求上创建 OxygenDataContext 的新实例。
感谢您的帮助。
更新 2
当我像下面这样修改 Unity 确认时:
container.RegisterType<IDbContext, OxygenDataContext>(new PerRequestLifetimeManager());
我坚持认为只有 1 个单一实例,但它似乎无法正常工作,因为我不断收到相同的错误。
更新 3
我已更改 Unity 配置以解析 IDbContext,它是一个带有“PerResolveLifetimeManager”的 DbContext,使用以下代码:
container.RegisterType<IDbContext, OxygenDataContext>(new PerResolveLifetimeManager());
这意味着每个解析调用都应该创建一个“OxygenDataContext”的新实例,还是我不正确?
在我的 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, IDbContext>(context, this);
settingRepository = new Repository<Setting, IDbContext>(context, this);
siteRepository = new VersionedRepository<Site, int, IDbContext>(context, this);
pageRepository = new VersionedRepository<Page, int, IDbContext>(context, this);
layoutRepository = new VersionedRepository<Layout, int, IDbContext>(context, this);
assemblyRepository = new VersionedRepository<Assembly, int, IDbContext>(context, this);
logRepository = new Repository<Log, IDbContext>(context, this);
}
所以这应该意味着每个存储库都获得了它自己唯一的“IDbContext”实例,但是它并没有按预期工作。
更新 4
我已经设法解决了自己的问题,请耐心等待,因为我正在编写解决方案作为对这篇文章的回答。
更新 5
它似乎不起作用。在这里查看我认为可行的解决方案:
我调整了 IUnitOfWork 接口以实现 IDisposeable 接口,然后将实现重新调整为以下内容:
protected virtual void Dispose(bool disposing)
{
if (disposing) { Context = null; }
}
public void Dispose()
{
Dispose(true);
}
但是,它不起作用。我在这里有点迷路了,所以如果有人知道解决方案:-)
更新 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);
}
我也尝试将代码更改为以下内容,但这也不起作用:
/// <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);
}
我仍然收到错误消息:“底层提供程序在打开时失败”,内部异常显示“连接未关闭。连接的当前状态为正在连接。”
您会看到 UnitOfWork 的构造函数确实采用了 IDbContext 实例,并且所有存储库都是使用该实例构造的。
我正在使用 Unity,我的 IDbContext 的注册需要以下代码:
container.RegisterType<IDbContext, OxygenDataContext>();
在我的 Unity 配置中,我还注册了 IUnitOfWork 接口:
container.RegisterType<IUnitOfWork, UnitOfWork>(new PerRequestLifetimeManager());
我确实感觉错误出在 Unity 注册或 UnitOfWork 中的某个地方,但我似乎没有找到。
【问题讨论】:
-
内部异常是什么?您的图像模糊,很难阅读内部异常。
-
确实,图像有点模糊。内部异常是:“连接未关闭。连接的当前状态为正在连接。”
-
您不是偶然在线程之间共享同一个存储库吗?因为您对 DbContext 注册所做的一切都很好。您如何解析存储库本身?
-
对不起,我不太明白你的问题,我发布的更新不是很清楚吗?
-
只显示创建和使用存储库的代码。我相信这就是问题所在。
标签: c# multithreading entity-framework