刷新后返回旧数据

时间:2018-09-16 15:14:54

标签: c# asp.net-mvc nhibernate asp.net-core-mvc

我正在将 TransactionScope nHibernate 一起使用。为了处理嵌套事务,我与 TransactionScope 一起创建了一个帮助器类。我的 SessionFactory

 public class SessionFactory
    {
        [ThreadStatic]
        private static ISessionFactory iSessionFactory;
        [ThreadStatic]
        protected static ISession session;
        private static object syncRoot = new Object();

        private static void buildSessionFactory()
        {
            lock (syncRoot)
            {
                if (session == null)
                {
                    if (iSessionFactory == null)
                    {
                        Configuration configuration = new Configuration().Configure("hibernate.cfg.xml");
                        Assembly assembly = Assembly.GetCallingAssembly();
                        iSessionFactory = configuration.BuildSessionFactory();
                    }
                    if (session != null && session.IsOpen)
                        session.Dispose();
                    CurrentSessionContext.Bind(iSessionFactory.OpenSession());
                    session = iSessionFactory.OpenSession();
                }
            }
        }

        public static ISession OpenSession
        {
            get
            {
                if (session == null || !session.IsOpen)
                {
                    session = null;
                    buildSessionFactory();
                }
                return session;
            }
        }
    }

配置文件名为 hibernate.cfg.xml ,并且为:

<configuration>
  <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
    <session-factory>
      <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
      <property name="connection.driver_class">
        NHibernate.Driver.MySqlDataDriver
      </property>
      <property name="dialect">NHibernate.Dialect.MySQL55InnoDBDialect</property>
      <property name="connection.connection_string">connection string here</property>
      <property name="current_session_context_class">thread_static</property>
      <property name="show_sql">true</property>
      <property name="generate_statistics">true</property>
      <mapping assembly="assembly name here"/>
      <!-- Here -->
    </session-factory>
  </hibernate-configuration>
  <system.transactions>
    <machineSettings maxTimeout="00:00:60" />
  </system.transactions>
</configuration>

用于管理嵌套交易的帮助程序类:

  public class TransactionScopeHelper : SessionFactory, iTransactionScopeHelper
    {
        public static int count = 0;
        public TransactionScope getTransactionScope()
        {
            if (count == 0)
            {
                if (session != null)
                    session.Clear();
            }
            count++;
            return new TransactionScope(TransactionScopeOption.Required);
        }

        public void complete(TransactionScope tx)
        {
            count--;
            if (count == 0)
            {
                session.Flush();
                session = null;
            }
            tx.Complete();
        }

        public void rollbackTransaction()
        {
            count = 0;
            session = null;
        }
    }

Helper类仅在服务中使用,而在存储库中不使用 服务中使用助手的示例:

public void updateCategory(CategoryDto category_dto)
{
 try
   {
    using (TransactionScope tx = transactionScopeHelper.getTransactionScope())
     {
      //works here
      transactionScopeHelper.complete(tx);
     }
   }
   catch(Exception)
   {
    transactionScopeHelper.rollbackTransaction();
    throw;
    }
}

存储库中的功能示例:

 public T getById(long id)
 {
  ISession session = SessionFactory.OpenSession;
  return session.Get<T>(id);
 }

每当我更新一些实体时,在刷新几次后就会显示旧数据,而在刷新一些新数据后会再次显示。这几乎是连续的。为什么会出现这个问题?任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:2)

这里发生了很多“不寻常”的事情,我几乎不知道从哪里开始。

SessionFactory

NHibernate的会话工厂在应用程序启动时(或在第一次需要时)已进行了一次ONCE的初始化,然后该实例将在程序运行期间存活并在所有线程之间共享。通常,我们不希望每个线程都有一个单独的实例(就像ThreadStatic一样)。反复初始化会严重影响性能。

buildSessionFactory()将在存在会话的情况下处理该会话-但除非session为null,否则它将无法获取该代码,所以我不明白这里的意图是什么。

在buildSessionFactory()的结尾,iSessionFactory.OpenSession()被调用了两次!一次就足够了。

您正在配置文件中设置current_session_context_class,然后调用CurrentSessionContext.Bind()。因此,您无需维护自己的线程静态会话变量。这就是CurrentSessionContext的作用。

最终必须处置会话。因此,调用名为OpenSession的方法意味着我们得到一个新的会话,该会话负责关闭。但是您自己的OpenSession()可以多次返回相同的会话,因此很难理解到底是谁负责关闭该会话。最好将其命名为CurrentSession或类似名称。

TransactionScopeHelper

这也是不可能理解的。引用了变量session,但未显示此变量的定义和设置。代码不完整。在某些时候,会话引用被设置为null,但是没有尝试处置它,这是强制性的。

在会话上调用Clear()将删除会话中的所有状态,并使NHibernate失去对所有已加载对象的跟踪,因此将无法执行脏检查并自动持久化。其他代码需要记住要仔细地重新添加所有内容。

代码未显示会话,事务和事务范围的实际创建方式和时间。无法判断互动是否正确。会话是否知道交易范围?

最后,回答您的问题:“我为什么会遇到这个问题?”

对不起,但是整个情况看起来一团糟。凌乱的代码等于凌乱的结果。当然,除非我上面提到的问题是由于部分复制粘贴导致重要部分遗漏所致。