我目前正在編寫一個依賴於數據庫的應用程序,而且我正在使用Entity Framework(根據Nuget 6.1.1版)。C#通用倉庫 - 工作單元 - 線程安全
現在我已經寫了一個存儲庫模式,它看起來像以下:
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
}
我確實有從這個庫繼承的類,但我會離開他們超出範圍的時刻。現在,當我做一個存儲庫上的獲取,我檢索數據,但是當我執行2獲取呼叫在sime時間(我只是打開2個瀏覽器窗口與相同的url並執行它們),然後下面的錯誤仍彈出:
類型的異常「System.Data.Entity.Core.EntityException」 發生EntityFramework.SqlServer.dll但在用戶 代碼
附加信息沒有被處理的:底層提供商在Open上失敗。
這裏有一個小圖像,以提供儘可能詳細的資料可能:
現在,我知道,在默認情況下實體Framwork的DbContext不是線程安全的,所以我知道我應該做一些事情來使其線程安全,但我只是不知道如何做到這一點。
可以anybode提供我的任何指導如何實現這一目標? 另外,我對IDisposeable沒有太多經驗,所以如果你建議在某個地方實現這一點,那麼你應該非常友好地向我提供一些關於如何實現這一點的信息。
重要的東西要提的是,我使用的是統一管理我的對象,你可以在這裏找到的配置:
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
}
更新
據我,這是團結,因爲我這是造成這種現象使用:
container.RegisterType<IDbContext, OxygenDataContext>();
這意味着每個請求都不會創建OxygenDataContext的新實例。
感謝您的幫助。
更新2
當我修改統一confiruation類似如下:
container.RegisterType<IDbContext, OxygenDataContext>(new PerRequestLifetimeManager());
我因子評分會有隻有1單一實例,但似乎它不工作,因爲我一直在接收到相同的錯誤。
更新3
我已經改變了統一配置,以解決IDbContext,這是一個的DbContext用「PerResolveLifetimeManager」使用下面的代碼:
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實例和所有的倉庫都與同樣的實例構造。
我使用的是團結,我IDbContext的註冊採取以下代碼:
container.RegisterType<IDbContext, OxygenDataContext>();
在我的統一配置,我也做註冊IUnitOfWork接口:
container.RegisterType<IUnitOfWork, UnitOfWork>(new PerRequestLifetimeManager());
我有感覺ŧ該錯誤是在Unity註冊或UnitOfWork中的某處,但我似乎沒有找到它。
有什麼內部異常?你的圖像很模糊,很難讀出內部的異常。 – Michael 2014-09-19 09:17:36
事實上,圖像有點模糊。內部例外情況是:「連接未關閉,連接的當前狀態正在連接。」 – Complexity 2014-09-19 09:19:17
難道你不是偶然在共享線程之間的**庫**嗎?因爲你使用DbContext註冊是可以的。你如何解決存儲庫本身? – 2014-09-19 09:46:17