多线程与流利的nhibernate [英] multithreading with fluent nhibernate
问题描述
private ISessionFactory GetSessionFactory(string sessionFactoryConfigPath)
{
GetFullSessionFactoryFor(sessionFactoryConfigPath); $!$ b while(!sessionFactoryReady)Thread.Sleep(1000);
return(ISessionFactory)sessionFactories [sessionFactoryConfigPath];
$ b private void GetFullSessionFactory(string sessionFactoryConfigPath)
{
ThreadPool.QueueUserWorkItem(state =>
{
ISessionFactory sessionFactory = null;
FluentConfiguration fluentConfiguration = fluentConfiguration.ExposeConfiguration(c => c.SetProperty(sessionfactoryname,somevalue))
.Mappings(m =>
{
m.FluentMappings
.AddFromAssembly(Assembly.Load(nameofassembly))$ b $ .Conventions.Add(DefaultLazy.Always(),
OptimisticLock.Is(x => x .All()),
DynamicUpdate.AlwaysTrue(),
DynamicInsert.AlwaysFalse(),
DefaultCascade.None()
)
.Conventions.AddFromAssemblyOf<SomeConvention>();
}
);
sessionFactory = fluentConfiguration.BuildSessionFactory();
});
我在主线程上创建了minisession工厂(这里没有显示)和第二个线程的完整会话工厂。
问题是,当它碰到buildsessionfactory代码不会返回。我做对了吗?
public class NHibernateBaseDAO< T>
{
public NHibernateBaseDAO(string sessionFactoryConfigPath,int sessionId)
{
SessionFactoryConfigPath = sessionFactoryConfigPath;
SessionId = sessionId;
public bool Save(T entity)
{
bool saveSuccessful = true;
尝试
{
NHibernateSession.Save(entity);
catch(NHibernate.HibernateException)
{
saveSuccessful = false;
}
返回saveSuccessful;
}
public bool SaveOrUpdate(T entity)
{
bool saveSuccessful = true;
尝试
{
NHibernateSession.SaveOrUpdate(entity);
catch(NHibernate.HibernateException)
{
saveSuccessful = false;
}
返回saveSuccessful;
public void Delete(T entity)
{
NHibernateSession.Delete(entity);
$ b public void CommitChanges()
{
if(NHibernateSessionManager.Instance.HasOpenTransactionOn(SessionFactoryConfigPath,this.SessionId))
{
NHibernateSessionManager.Instance.GetSessionFrom(SessionFactoryConfigPath,this.SessionId).Flush();
NHibernateSessionManager.Instance.CommitTransactionOn(SessionFactoryConfigPath,this.SessionId);
}
else
{
NHibernateSessionManager.Instance.GetSessionFrom(SessionFactoryConfigPath,this.SessionId).Flush();
$ b $ public void BeginTransaction()
{
NHibernateSessionManager.Instance.BeginTransactionOn(SessionFactoryConfigPath,this.SessionId);
$ b $ public void RollbackTransaction()
{
NHibernateSessionManager.Instance.RollbackTransactionOn(SessionFactoryConfigPath,this.SessionId);
public bool IsDirty()
{
return NHibernateSession.IsDirty();
}
public IQueryable< T> Query(){
return(IQueryable< T>)NHibernateSession.Query< T>();
$ b保护ISession NHibernateSession
{
获得
{
返回NHibernateSessionManager.Instance.GetSessionFrom(SessionFactoryConfigPath,this.SessionId);
}
}
保护只读字符串SessionFactoryConfigPath;
protected int SessionId;
protected System.Data.IDbConnection DbConnection
{
get {return NHibernateSessionManager.Instance.GetDbConnection(SessionFactoryConfigPath,this.SessionId); }
}
///< summary>
///返回对象数组列表。将其用于常规查询
///< / summary>
public System.Collections.IEnumerable GetSqlQuery(string queryString,IList< Criterion> criteria,Type returnType)
{
queryString + = CriteriaToSql(criterion);
返回NHibernateSession.CreateQuery(queryString).Enumerable();
}
protected ICriteria AddCriteria(IList< Criterion> criteria)
{
ICriteria criteria = NHibernateSession.CreateCriteria(persistentType); (标准中的标准标准)
{
switch(标准比较)
{
case SqlComparison.StartsWith:
标准。 Add(Restrictions.InsensitiveLike(Criterium.Property,Criterium.Value1.ToString(),MatchMode.Start));
break;
case SqlComparison.Contains:
criteria.Add(Restrictions.InsensitiveLike(criterium.Property,criterium.Value1.ToString(),MatchMode.Anywhere));
break;
case SqlComparison.Equals:
criteria.Add(Restrictions.Eq(criterium.Property,criterium.Value1));
break;
case SqlComparison.Between:
criteria.Add(Restrictions.Between(criterium.Property,Criterium.Value1,criterium.Value2));
break;
case SqlComparison.MoreThan:
criteria.Add(Restrictions.Gt(criterium.Property,criterium.Value1));
break;
case SqlComparison.LessThan:
criteria.Add(Restrictions.Lt(criterium.Property,criterium.Value2));
break;
case SqlComparison.InList:
criteria.Add(Restrictions.In(criterium.Property,(System.Collections.IList)criterium.Value1));
break;
}
}
退货标准;
protected string CriteriaToSql(IList< Criterion> criteria)
{
}
///< summary>
///获取数据的分隔符,默认为'除非数据类型
///< / summary>
protected string [] GetDelimiter(object value)
{
}
public class Criterion
{
public Criterion(string property,SqlComparison比较,对象值1)
{
Property = property;
比较=比较;
Value1 = value1;
public Criterion(字符串属性,SqlComparison比较,对象value1,对象value2)
{
Property = property;
比较=比较;
Value1 = value1;
Value2 = value2;
public Criterion(字符串属性,SqlComparison比较,对象value1,bool不)
{
Property = property;
比较=比较;
Value1 = value1;
不=不是;
$ b $公共标准(字符串属性,SqlComparison比较,对象value1,对象value2,bool不)
{
Property = property;
比较=比较;
Value1 = value1;
Value2 = value2;
不=不是;
}
public string Property {get;组; }
public bool Not {get;组; }
public SqlComparison Comparison {get;组; }
公共对象Value1 {get;组; }
公共对象Value2 {get;组; }
public enum SqlComparison {StartsWith,Contains,Equals,Between,MoreThan,LessThan,InList}
}
请最后一个问题。我正在使用泛型类来访问sessionfactory,所以我不能显式访问minisession。在这种情况下,如何在完全会话不可用的情况下访问基于特定实体的minisession,如何在完全会话工厂可用的情况下访问minisession。
您从未将sessionfactoryready设置为true
更新:更完整的示例。 code> void Main()
{
Database.InitRealFactoryAsync(< sessionFactoryConfigPath>);
var minifactory = Database.GetMiniFactory(< sessionFactoryConfigPath>);
//用minifactory做一些事情
var realsessionfactory = Database.SessionFactory;
//做真实工厂的东西
}
静态类数据库
{
private static ISessionFactory sessionFactory;
public void InitRealFactoryAsync(string sessionFactoryConfigPath)
{
ThreadPool.QueueUserWorkItem(state =>
{
sessionFactory = Fluently.Configure()
.Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.Load(nameofassembly))
.Conventions.Add(DefaultLazy.Always(),
OptimisticLock.Is(x => ; x.All()),
DynamicUpdate.AlwaysTrue(),
DynamicInsert.AlwaysFalse(),
DefaultCascade.None())
.Conventions.AddFromAssemblyOf< FoxproDateConvention>( ))
.BuildSessionFactory();
});
$ b $ public ISessionFactory GetMiniFactory(string sessionFactoryConfigPath)
{
var assembly = Assembly.Load(nameofassembly);
return Futual.Configure()
.Mappings(m => m.FluentMappings.Add(assembly.GetTypes()。Where(Filter).ToArray())
.Conventions.Add (DefaultLazy.Always(),
OptimisticLock.Is(x => x.All()),
DynamicUpdate.AlwaysTrue(),
DynamicInsert.AlwaysFalse(),
DefaultCascade.None())
.Conventions.AddFromAssemblyOf< FoxproDateConvention>())
.BuildSessionFactory();
$ b $ public static ISessionFactory SessionFactory
{
while(sessionFactory == null)Thread.Sleep(1000);
return sessionFactory;
$ b code
$ b UpdateUpdate:
$ b $ pre $ code $ void $($)
Database.InitRealFactoryAsync(< sessionFactoryConfigPath>);
Database.InitMiniFactory(< sessionFactoryConfigPath>);
使用(var session = Database.GetSession(true))
{
//做一些minifactory足够的东西
}
使用(var session = Database.GetSession())
{
//做真正的工厂
的东西}
...
}
// class Database
public ISession GetSession()
{
return GetSession(false);
public ISession GetSession(bool miniFactoryIsEnough)
{
if(realSessionfactory!= null)
return realSessionfactory.OpenSession();
if(miniFactoryIsEnough)
return miniSessionfactory.OpenSession();
else
{
while(realSessionFactory == null)Thread.Sleep(1000);
返回realSessionfactory.OpenSession();
$ b更新:仅基于特定实体的访问微分
您需要指定您要在会话中使用的类型:
{
if(fullSessionfactory!= null)
return realSessionfactory.OpenSession();
if(miniFactory.GetClassMetadata(persistentType)!= null)
return miniSessionfactory.OpenSession();
else
{
// minifactory不包含所需的类型,等待完整的工厂
while(fullSessionFactory == null)Thread.Sleep(1000);
返回fullSessionfactory.OpenSession();
$ / code $ / pre
一些额外的建议
$catch(NHibernate.HibernateException)
- 你失去了有价值的信息,当调用返回false时,调用代码不能真正决定怎么做
- 会话状态不一致请参阅 https://stackoverflow.com/a/1819150/671619
FlushMode应该是
Flushmode.Commit
和 public void CommitChanges()
可以写成 var session = NHibernateSession;
if(session.Transaction.IsActiv)
{
session.Transaction.Commit();
}
删掉了整个sessionId的东西,因为它似乎没有提供任何价值。举行会议,而不是sessionId而不是
private ISessionFactory GetSessionFactory(string sessionFactoryConfigPath) { GetFullSessionFactoryFor(sessionFactoryConfigPath); while (!sessionFactoryReady) Thread.Sleep(1000); return (ISessionFactory)sessionFactories[sessionFactoryConfigPath]; } private void GetFullSessionFactory(string sessionFactoryConfigPath) { ThreadPool.QueueUserWorkItem(state => { ISessionFactory sessionFactory=null; FluentConfiguration fluentConfiguration = fluentConfiguration.ExposeConfiguration(c => c.SetProperty("sessionfactoryname","somevalue")) .Mappings(m => { m.FluentMappings .AddFromAssembly(Assembly.Load("nameofassembly")) .Conventions.Add(DefaultLazy.Always(), OptimisticLock.Is(x => x.All()), DynamicUpdate.AlwaysTrue(), DynamicInsert.AlwaysFalse(), DefaultCascade.None() ) .Conventions.AddFromAssemblyOf<"SomeConvention">(); } ); sessionFactory = fluentConfiguration.BuildSessionFactory(); }); }
I am creating minisession factory on main thread(not shown here) and full session factory on second thread. The problem is when it hits buildsessionfactory the code never returns back.Am i doing it right?
public class NHibernateBaseDAO<T>
{
public NHibernateBaseDAO(string sessionFactoryConfigPath, int sessionId)
{
SessionFactoryConfigPath = sessionFactoryConfigPath;
SessionId = sessionId;
public bool Save(T entity)
{
bool saveSuccessful = true;
try
{
NHibernateSession.Save(entity);
}
catch (NHibernate.HibernateException)
{
saveSuccessful = false;
}
return saveSuccessful;
}
public bool SaveOrUpdate(T entity)
{
bool saveSuccessful = true;
try
{
NHibernateSession.SaveOrUpdate(entity);
}
catch (NHibernate.HibernateException)
{
saveSuccessful = false;
}
return saveSuccessful;
}
public void Delete(T entity)
{
NHibernateSession.Delete(entity);
}
public void CommitChanges()
{
if (NHibernateSessionManager.Instance.HasOpenTransactionOn(SessionFactoryConfigPath, this.SessionId))
{
NHibernateSessionManager.Instance.GetSessionFrom(SessionFactoryConfigPath, this.SessionId).Flush();
NHibernateSessionManager.Instance.CommitTransactionOn(SessionFactoryConfigPath, this.SessionId);
}
else
{
NHibernateSessionManager.Instance.GetSessionFrom(SessionFactoryConfigPath, this.SessionId).Flush();
}
}
public void BeginTransaction()
{
NHibernateSessionManager.Instance.BeginTransactionOn(SessionFactoryConfigPath, this.SessionId);
}
public void RollbackTransaction()
{
NHibernateSessionManager.Instance.RollbackTransactionOn(SessionFactoryConfigPath, this.SessionId);
}
public bool IsDirty()
{
return NHibernateSession.IsDirty();
}
public IQueryable<T> Query() {
return (IQueryable<T>)NHibernateSession.Query<T>();
}
protected ISession NHibernateSession
{
get
{
return NHibernateSessionManager.Instance.GetSessionFrom(SessionFactoryConfigPath, this.SessionId);
}
}
protected readonly string SessionFactoryConfigPath;
protected int SessionId;
protected System.Data.IDbConnection DbConnection
{
get { return NHibernateSessionManager.Instance.GetDbConnection(SessionFactoryConfigPath, this.SessionId); }
}
/// <summary>
/// Return a list of object arrays. use this for general queries
/// </summary>
public System.Collections.IEnumerable GetSqlQuery(string queryString, IList<Criterion> criterion, Type returnType)
{
queryString += CriteriaToSql(criterion);
return NHibernateSession.CreateQuery(queryString).Enumerable();
}
protected ICriteria AddCriteria(IList<Criterion> criterion)
{
ICriteria criteria = NHibernateSession.CreateCriteria(persistentType);
foreach (Criterion criterium in criterion)
{
switch (criterium.Comparison)
{
case SqlComparison.StartsWith:
criteria.Add(Restrictions.InsensitiveLike(criterium.Property, criterium.Value1.ToString(), MatchMode.Start));
break;
case SqlComparison.Contains:
criteria.Add(Restrictions.InsensitiveLike(criterium.Property, criterium.Value1.ToString(), MatchMode.Anywhere));
break;
case SqlComparison.Equals:
criteria.Add(Restrictions.Eq(criterium.Property, criterium.Value1));
break;
case SqlComparison.Between:
criteria.Add(Restrictions.Between(criterium.Property, criterium.Value1, criterium.Value2));
break;
case SqlComparison.MoreThan:
criteria.Add(Restrictions.Gt(criterium.Property, criterium.Value1));
break;
case SqlComparison.LessThan:
criteria.Add(Restrictions.Lt(criterium.Property, criterium.Value2));
break;
case SqlComparison.InList:
criteria.Add(Restrictions.In(criterium.Property, (System.Collections.IList)criterium.Value1));
break;
}
}
return criteria;
}
protected string CriteriaToSql(IList<Criterion> criterion)
{
}
/// <summary>
/// Get delimiter for data, defaults to ' unless specifed for data type
/// </summary>
protected string[] GetDelimiter(object value)
{
}
public class Criterion
{
public Criterion(string property, SqlComparison comparison, object value1)
{
Property = property;
Comparison = comparison;
Value1 = value1;
}
public Criterion(string property, SqlComparison comparison, object value1, object value2)
{
Property = property;
Comparison = comparison;
Value1 = value1;
Value2 = value2;
}
public Criterion(string property, SqlComparison comparison, object value1, bool not)
{
Property = property;
Comparison = comparison;
Value1 = value1;
Not = not;
}
public Criterion(string property, SqlComparison comparison, object value1, object value2, bool not)
{
Property = property;
Comparison = comparison;
Value1 = value1;
Value2 = value2;
Not = not;
}
public string Property { get; set; }
public bool Not { get; set; }
public SqlComparison Comparison { get; set; }
public object Value1 { get; set; }
public object Value2 { get; set; }
}
public enum SqlComparison { StartsWith, Contains, Equals, Between, MoreThan, LessThan, InList }
}
one last question please. I am using generic class to access sessionfactory so i cannot explicitly access the minisession. with this how do i access minisession based only on certain entities if the full session is not available and full session factory when it is available.
you never set sessionfactoryready to true
Update: a more complete example.
void Main()
{
Database.InitRealFactoryAsync("<sessionFactoryConfigPath>");
var minifactory = Database.GetMiniFactory("<sessionFactoryConfigPath>");
// Do some stuff with minifactory
var realsessionfactory = Database.SessionFactory;
// Do stuff with real factory
}
static class Database
{
private static ISessionFactory sessionFactory;
public void InitRealFactoryAsync(string sessionFactoryConfigPath)
{
ThreadPool.QueueUserWorkItem(state =>
{
sessionFactory = Fluently.Configure()
.Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.Load("nameofassembly"))
.Conventions.Add(DefaultLazy.Always(),
OptimisticLock.Is(x => x.All()),
DynamicUpdate.AlwaysTrue(),
DynamicInsert.AlwaysFalse(),
DefaultCascade.None())
.Conventions.AddFromAssemblyOf<FoxproDateConvention>())
.BuildSessionFactory();
});
}
public ISessionFactory GetMiniFactory(string sessionFactoryConfigPath)
{
var assembly = Assembly.Load("nameofassembly");
return Fluently.Configure()
.Mappings(m => m.FluentMappings.Add(assembly.GetTypes().Where(Filter).ToArray())
.Conventions.Add(DefaultLazy.Always(),
OptimisticLock.Is(x => x.All()),
DynamicUpdate.AlwaysTrue(),
DynamicInsert.AlwaysFalse(),
DefaultCascade.None())
.Conventions.AddFromAssemblyOf<FoxproDateConvention>())
.BuildSessionFactory();
}
public static ISessionFactory SessionFactory
{
get {
while (sessionFactory == null) Thread.Sleep(1000);
return sessionFactory;
}
}
}
UpdateUpdate:
void Main()
{
Database.InitRealFactoryAsync("<sessionFactoryConfigPath>");
Database.InitMiniFactory("<sessionFactoryConfigPath>");
using (var session = Database.GetSession(true))
{
// Do some stuff where minifactory is enough
}
using (var session = Database.GetSession())
{
// Do stuff with real factory
}
...
}
// class Database
public ISession GetSession()
{
return GetSession(false);
}
public ISession GetSession(bool miniFactoryIsEnough)
{
if (realSessionfactory != null)
return realSessionfactory.OpenSession();
if (miniFactoryIsEnough)
return miniSessionfactory.OpenSession();
else
{
while (realSessionFactory == null) Thread.Sleep(1000);
return realSessionfactory.OpenSession();
}
}
Update: "access minisession based only on certain entities"
you need to specify the type you want to use in the session:
public ISession GetSession(Type persistentType)
{
if (fullSessionfactory != null)
return realSessionfactory.OpenSession();
if (miniFactory.GetClassMetadata(persistentType) != null)
return miniSessionfactory.OpenSession();
else
{
// minifactory doesnt contain the type needed, wait for full factory
while (fullSessionFactory == null) Thread.Sleep(1000);
return fullSessionfactory.OpenSession();
}
}
some additional advice
do not catch (NHibernate.HibernateException)
- you lose valuable information and the calling code can't really decide what to do when false is returned
- session state is inconsistent see https://stackoverflow.com/a/1819150/671619
FlushMode should be Flushmode.Commit
and public void CommitChanges()
can be written as
var session = NHibernateSession;
if (session.Transaction.IsActiv)
{
session.Transaction.Commit();
}
cut out the whole sessionId stuff as it seems to provide no value. hold the session instead of sessionId instead
这篇关于多线程与流利的nhibernate的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!