这听起来像是一个重复的问题,但我不相信。
这是我得到的错误,这听起来很常见。但我只是间歇性地得到这个错误。对于我访问我网站的用户数量,我估计这只发生在大约5%的时间。
以下是代码:
private TopWrestlers FillTopWrestlers()
{
try
{
var mostRecent = _wrestlerRankingRepo.Query().OrderByDescending(wr => wr.Season).First().Season;
var currentSeason = _configService.GetCurrentSeason();
if (mostRecent > currentSeason)
return null;
var tws =
_wrestlerRankingRepo.GetRankedWrestlers(currentSeason)
.Where(wr => wr.Rank <= 3)
.OrderBy(wr => wr.Rank)
.Select(wr => wr.Wrestler);
return new TopWrestlers
{
_125 = tws.FirstOrDefault(w => w.Roster.WeightClass == 125),
_133 = tws.FirstOrDefault(w => w.Roster.WeightClass == 133),
_141 = tws.FirstOrDefault(w => w.Roster.WeightClass == 141),
_149 = tws.FirstOrDefault(w => w.Roster.WeightClass == 149),
_157 = tws.FirstOrDefault(w => w.Roster.WeightClass == 157),
_165 = tws.FirstOrDefault(w => w.Roster.WeightClass == 165),
_174 = tws.FirstOrDefault(w => w.Roster.WeightClass == 174),
_184 = tws.FirstOrDefault(w => w.Roster.WeightClass == 184),
_197 = tws.FirstOrDefault(w => w.Roster.WeightClass == 197),
_285 = tws.FirstOrDefault(w => w.Roster.WeightClass == 285)
};
}
catch (Exception ex)
{
_errorService.LogError(new Exception("Exception occurred trying to retrieve the top wrestlers for each weight on the home page. " + ex.Message, ex));
return null;
}
}
我在第一行收到错误:
_wrestlerRankingRepo.Query().OrderByDescending(wr => wr.Season).First().Season;
我知道repo有数据。特别是因为它在95%的时间内恢复正常。
有关如何解决如何修复此错误的任何帮助?我甚至无法重新创造这个问题。这是在该网站的主页上。所以我不认为这与新的会议有关......我在这里不知所措。
这是基本回购代码:
public abstract class BaseRepository<TRecord, TMap> : IBaseRepository<TRecord>
where TRecord : class, IEntity
where TMap : ClassMap<TRecord>, new()
{
private static Member _primaryKeyMember;
protected ISession Session;
protected IUserIdentity UserIdentity;
public BaseRepository(ISession session)
{
Session = session;
}
public BaseRepository(ISession session, IUserIdentity userIdentity)
{
Session = session;
UserIdentity = userIdentity;
}
public void Delete(TRecord obj)
{
Session.Delete(obj);
Session.Flush();
}
public void Save(TRecord value)
{
Session.SaveOrUpdate(value);
Session.Flush();
}
public void Save(IEnumerable<TRecord> values)
{
using (ITransaction sessionTransaction = Session.BeginTransaction())
{
try
{
foreach (TRecord value in values)
Session.SaveOrUpdate(value);
sessionTransaction.Commit();
Session.Flush();
}
catch
{
sessionTransaction.Rollback();
throw;
}
}
}
public virtual IQueryable<TRecord> Query()
{
return Session.Query<TRecord>();
}
}
public interface IBaseRepository<TRecord>
where TRecord : IEntity
{
void Delete(TRecord obj);
void Save(TRecord value);
void Save(IEnumerable<TRecord> values);
IQueryable<TRecord> Query();
}
这是WrestlerRankingRepo代码:
public class WrestlerRankingRepository : BaseRepository<WrestlerRanking, WrestlerRankingMap>, IWrestlerRankingRepository
{
public WrestlerRankingRepository(ISession session) : base(session)
{
}
public IQueryable<WrestlerRanking> GetRankedWrestlers(int season)
{
return base.Query()
.Where(wr => wr.Rank != null)
.Where(wr => wr.Season == season)
.Where(wr => wr.IsCurrent)
.Where(wr => !wr.Wrestler.LastName.StartsWith("("));
}
public IQueryable<WrestlerRanking> GetRankedWrestlers(int season, int weight)
{
return GetRankedWrestlers(season)
.Where(wr => wr.WeightClass == weight);
}
public IQueryable<WrestlerRanking> GetRankedWrestlersWithMatches(int season)
{
return GetRankedWrestlers(season);
// for some reason it hates this: .Where(w => w.CurrentStats != null)
}
public IQueryable<WrestlerRanking> GetRankedWrestlersWithMatches(int season, int weight)
{
return GetRankedWrestlers(season)
.Where(w => w.WeightClass == weight);
// for some reason it hates this: .Where(w => w.CurrentStats != null)
}
}
public interface IWrestlerRankingRepository : IBaseRepository<WrestlerRanking>
{
IQueryable<WrestlerRanking> GetRankedWrestlers(int season);
IQueryable<WrestlerRanking> GetRankedWrestlers(int season, int weight);
IQueryable<WrestlerRanking> GetRankedWrestlersWithMatches(int season);
IQueryable<WrestlerRanking> GetRankedWrestlersWithMatches(int season, int weight);
}
SessionFactory代码:
public static class SessionFactory
{
private static ISessionProvider _instance;
public static ISessionProvider Instance
{
get
{
if (_instance == null)
{
string sessionClass = ConfigurationManager.AppSettings["SessionProvider"];
if (string.IsNullOrWhiteSpace(sessionClass))
throw new ConfigurationErrorsException("Session Provider must be specified in the app.config");
_instance = (ISessionProvider)Activator.CreateInstance(Type.GetType(sessionClass));
}
return _instance;
}
}
[Obsolete]
public static ISession GetCurrentSession()
{
return GetSession();
}
public static ISession GetSession()
{
return Instance.GetSession();
}
public static string GetConnectionString()
{
return ConfigurationManager.ConnectionStrings["WrestleStat"].ConnectionString;
}
public static IPersistenceConfigurer BuildConfig()
{
return MsSqlConfiguration.MsSql2008.ConnectionString(GetConnectionString());
}
public static void BuildMappings(MappingConfiguration mappings)
{
mappings.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly());
}
}
public class SqlStatementInterceptor : EmptyInterceptor
{
public override SqlString OnPrepareStatement(SqlString sql)
{
Trace.WriteLine(sql.ToString());
return sql;
}
}
public interface ISessionProvider
{
ISession GetSession();
ISession OpenSession();
void CloseSession();
}
这是Ninject强制执行:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind(scanner => scanner
.From(new List<Assembly>
{
typeof (HomeController).Assembly,
typeof (Match).Assembly
})
.SelectAllClasses()
.BindAllInterfaces()
.Configure(b => b.InTransientScope())
);
kernel.Rebind<ISession>().ToMethod(icontext => SessionFactory.GetSession()).InRequestScope();
//kernel.Rebind<IUserIdentity>().ToMethod(i => MvcApplication.GetWebIdentity()).InRequestScope();
}
另一个相关的地方......
public class CoreWebSessionModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += OpenSession;
context.EndRequest += CloseSession;
}
private static void OpenSession(object sender, EventArgs e)
{
SessionFactory.Instance.OpenSession();
}
private static void CloseSession(object sender, EventArgs e)
{
SessionFactory.Instance.CloseSession();
}
public void Dispose()
{
}
}
再一次
public class CoreWebSessionProvider : ISessionProvider
{
private static ISessionFactory _holder;
private static ISessionFactory MySessionFactory
{
get
{
if (_holder == null)
{
_holder = GetFluentConfiguration().BuildSessionFactory();
}
return _holder;
}
}
public ISession GetSession()
{
return HttpContext.Current != null ? MySessionFactory.GetCurrentSession() : null;
}
public ISession OpenSession()
{
var session = MySessionFactory.OpenSession();
ManagedWebSessionContext.Bind(HttpContext.Current, session);
return session;
}
public void CloseSession()
{
var session = ManagedWebSessionContext.Unbind(HttpContext.Current, MySessionFactory);
if (session != null)
{
if (session.Transaction != null && session.Transaction.IsActive)
session.Transaction.Rollback();
//else
// session.Flush();
if (session.IsOpen)
session.Close();
}
}
private static FluentConfiguration GetFluentConfiguration()
{
return
Fluently.Configure()
.Database(SessionFactory.BuildConfig())
.ExposeConfiguration(BuildSchema)
.Mappings(SessionFactory.BuildMappings);
}
public static Configuration GetConfiguration()
{
return GetFluentConfiguration().BuildConfiguration();
}
private static void BuildSchema(Configuration config)
{
config.SetProperty("current_session_context_class", "managed_web");
}
public IStatelessSession GetStatelessSession()
{
return MySessionFactory.OpenStatelessSession();
}
}
答案 0 :(得分:1)
来自NHibernate documentation
(强调我的):
ISessionFactory是一个昂贵的创建线程安全对象,旨在由所有应用程序线程共享。 ISession是一种廉价的非线程安全对象,对于单个业务流程应该使用一次,然后丢弃
所以你不应该像这样分享你的会话对象。如果可能,仅在需要时创建一个并尽快销毁它。
一些关于上下文和生命周期的优秀further reading here,包括NHibernate。
答案 1 :(得分:1)
问题很可能是使用单个会话,
public static ISession GetSession()
{
return Instance.GetSession();
}
并且由于您的Web应用程序使用多个线程,并且每次都会返回相同的会话。根据定义,会话不是线程安全的。
最佳选择是配置您的DI以按请求注入新会话(如果您使用DI),例如Autofac
builder.Register(x => x.Resolve<ISessionFactory>().OpenSession())
.InstancePerHttpRequest();