Dot Net developer
Dot Net developer

Reputation: 436

Retrieving an object from one session and updating in another session nHibernate

I need to update customer details. For this, I have to retrieve the entity from another session from repository and in the service, I am updating that entity. When I do this, I get an error message saying:

The operation is not valid for the current state of the enlistment.

But if I updated the entity without retrieving it from database, everything works fine.

This is how I am trying to update in Service.

 Customer customer = customerService.getById(customer_payment.customer_id);
 customer.deductBalance(customer_payment.discount_received);
 customerService.updateCustomerDetails(customer);

This is my repository that updates the entity:

using (ISession session = SessionFactory.OpenSession)
  {
    using(ITransaction t = session.BeginTransaction())
        {
          session.SaveOrUpdate(customer);
           t.Commit();
        }
   }

This is my function that returns the entity of the given ID:

Customer customer;

using (ISession session = SessionFactory.OpenSession)
  {
   customer = session.Get<Customer>(customer_id);
  }
 return customer;

How can I solve this problem? Thanks in advance.

Edit 1: This is what my OpenSession does:

Configuration configuration = new Configuration().Configure("hibernate.cfg.xml");
Assembly assembly = Assembly.GetCallingAssembly();
configuration.AddAssembly(assembly);
iSessionFactory = configuration.BuildSessionFactory();
CurrentSessionContext.Bind(iSessionFactory.OpenSession());
return iSessionFactory.OpenSession();

Is it a good approach to open a new session everytime or should I use Singleton pattern in SessionFactory?

Upvotes: 2

Views: 2440

Answers (1)

Amit Joshi
Amit Joshi

Reputation: 16389

Detach the customer from first ISession before updating it with other. You have to expose Evict method on repository OR have to expose ISession outside your repository.

Customer customer = customerService.getById(customer_payment.customer_id);

customerService.Evict(customer);
//OR
customerRepository.Evict(customer);
//OR
customerService.Session.Evict(customer);
//OR something similar...

customer.deductBalance(customer_payment.discount_received);
customerService.updateCustomerDetails(customer);

Refer following:
https://ayende.com/blog/4282/nhibernate-cross-session-operations
What does NHibernate Session.Evict do?
Can I detach an object from an NHibernate session?

Edit (for your Update)

Is it a good approach to open a new session everytime or should I use Singleton pattern in SessionFactory?

This is opinion based question actually; but it is recommended that your ISession should be short lived.

That said, you can create new session for each database action. But by doing this, you are missing many ORM features like Session Level Cache, Lazy Loading, Change Tracking (UoW) etc.

You can choose to move your UoW on Request level (i.e. ISession per Request) where you can avail the benefit of ORM features; but again there are other issues associated with it. Refer following: https://stackoverflow.com/a/48092471/5779732
Should I transform Entity (Persistent) objects to DTO objects?

Upvotes: 2

Related Questions