nHibernate и несколько задач - PullRequest
       7

nHibernate и несколько задач

0 голосов
/ 27 августа 2018

Я пытаюсь улучшить производительность нашего приложения nHibernate (3.3.2.4000) (.NET 4.0). В настоящее время мы выполняем операции CRUD одна за другой, что отнимает много времени, поэтому я планировал использовать ConcurrentQueue и Tasks.

Я преобразовал свой код в это:

    public void ImportProductsFromXml(string path)
    {
        List<Product> products = Mapper.GetProducts(path);

        var addQueue = new ConcurrentQueue<Product>(productsToAddUpdate);
        var updateTasks = new List<Task>();
        for (int i = 0; i < 5; i++)
        {
            var taskId = i + 1;
            updateTasks.Add(Task.Factory.StartNew(() => ProcessAddQueue(taskId, products, addQueue)));
        }
    }

    private void ProcessAddQueue(int taskId, List<Product> products, ConcurrentQueue<Product> queue)
    {
        Product result = null;
        while (queue.TryDequeue(out result))
        {
            try
            {
                UpdateProducts(products, result);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(string.Format("ProcessAddQueue: taskId={0}, SKU={1}, ex={2}", taskId, result.ProductId, ex));
            }
        }
    }

    private void UpdateProducts(List<Product> productsFromFile, Product product)
    {
        ...code removed...
            CatalogItem parentItem = _catalogRepository.GetByCatalogItemId(category);
        ...code removed...
            _catalogRepository.Save(parentItem);
        ...code removed...
    }

    public CatalogItem GetByCatalogItemId(string catalogItemId)
    {
        using (ISession session = SessionFactory.OpenSession())
        {
            return session
                .CreateCriteria(typeof (CatalogItem))
                .Add(Restrictions.Eq("CatalogItemId", catalogItemId))
                .List<CatalogItem>().FirstOrDefault();
        }
    }

Метод «Сохранить» каталога catalog вызывает этот метод за кулисами:

public int Add(T entity)
    {
        using (ISession session = SessionFactory.OpenSession())
        using (ITransaction transaction = session.BeginTransaction())
        {
            var id = (int) session.Save(entity);
            transaction.Commit();
            return id;
        }
    }

Таким образом, моя идея состояла в том, чтобы создать параллельную очередь, содержащую все продукты, а затем обработать их 5 за раз.

Тем не менее, я получаю «Исключение прервано потоком»:

at System.WeakReference.get_Target()
at System.Transactions.Transaction.JitSafeGetContextTransaction(ContextData contextData)
at System.Transactions.Transaction.FastGetTransaction(TransactionScope currentScope, ContextData contextData, Transaction& contextTransaction)
at System.Transactions.Transaction.get_Current()
at NHibernate.Transaction.AdoNetWithDistributedTransactionFactory.EnlistInDistributedTransactionIfNeeded(ISessionImplementor session)
at NHibernate.Impl.SessionImpl.get_PersistenceContext()
at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsTransient(SaveOrUpdateEvent event)
at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event)
at NHibernate.Impl.SessionImpl.FireSave(SaveOrUpdateEvent event)
at NHibernate.Impl.SessionImpl.Save(Object obj)

Что я делаю не так?

1 Ответ

0 голосов
/ 27 августа 2018

Hibernate-сессии предназначены для использования в качестве единицы работы. Вы открываете сеанс, открываете в нем транзакцию, загружаете свою сущность, изменяете ее, вызываете сохранение, фиксируете / откатываете транзакцию и затем удаляете сеанс.

Вы должны использовать ОДИН сеанс для загрузки вашей сущности, а затем сохранить ее. В настоящее время вы загружаете объект с одним сеансом и сохраняете его с другим сеансом. В сочетании с одновременным доступом это может вызвать проблемы.

Попробуйте загрузить и сохранить объект в том же сеансе гибернации.

При использовании hibernate, как уже упоминалось, он должен быть полностью поточно-ориентированным. Обратите внимание, что один сеанс гибернации НЕ является потокобезопасным.

...