【问题标题】:multithreading with fluent nhibernate使用流畅的 nhibernate 进行多线程
【发布时间】:2012-02-06 18:59:36
【问题描述】:
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();

          });
}

我正在主线程上创建小型会话工厂(此处未显示),并在第二个线程上创建完整会话工厂。 问题是当它到达 buildsessionfactory 时,代码永远不会返回。我做得对吗?

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 }
 }

最后一个问题。我正在使用通用类来访问 sessionfactory,因此我无法显式访问 minisession。有了这个,如果完整会话不可用和完整会话工厂可用时,我如何仅基于某些实体访问迷你会话。

【问题讨论】:

    标签: fluent-nhibernate


    【解决方案1】:

    你永远不会将 sessionfactoryready 设置为 true

    更新:一个更完整的例子。

    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;
            }
        }
    }
    

    更新更新:

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

    更新:“仅基于某些实体访问 minisession”

    您需要指定要在会话中使用的类型:

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

    一些额外的建议

    不要catch (NHibernate.HibernateException)

    FlushMode 应该是Flushmode.Commitpublic void CommitChanges() 可以写成

    var session = NHibernateSession;
    if (session.Transaction.IsActiv)
    {
        session.Transaction.Commit();
    }
    

    删掉整个 sessionId 的东西,因为它似乎没有任何价值。保持会话而不是 sessionId

    【讨论】:

    • 有人能帮我解释一下为什么在上面的 builsessionfactory realsessionfactory 之后线程永远不会返回
    • 我不相信 buildsessionfactory 永远不会返回,它很可能是 GetSessionfactory()。请在一个简单的控制台应用程序中尝试我的代码,看看它是如何完成的
    • 当我将 nameofassembly 更改为其他东西以进行测试但不适用于它应该工作的那个时,它会起作用。当我删除线程它工作正常。我的意思是 sessionfactory 永远不会被创建。
    • 在您发布的代码中,sessionfactory 被分配给一个立即被丢弃的 local 变量。没有迹象表明将 sf 放入 sessionFactories 也没有将 sessionFactoryReady 设置为 true。还有什么是启动另一个线程并等到它完成?查看我的代码以查看线程在何处启动以及何时使用结果
    • 实际上这背后的逻辑是使用 minisession factory 并等待 fullsessionfactory 直到它准备好
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-14
    • 2016-01-17
    相关资源
    最近更新 更多