2

I have two entities, Customer and Account. A Customer has many accounts.

My mapping for Customer is :

<bag cascade="all" name="Accounts" table ="Accounts" mutable="true" inverse="true">
  <key>
    <column name="Customer_Id" />
  </key>
  <one-to-many class="Account, POCOEntities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</bag>

My mapping for Account is:

<many-to-one cascade="all" class="Customer, POCOEntities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="Customer">
  <column name="Customer_Id" />
</many-to-one>

In my application, I retrieve a customer based on their ID:

var customer = _customerRepository.GetById(custID);

I then try to get the customers first account with:

Account account = customer.Accounts.FirstOrDefault();

I then receive the following exception: "NHibernate.LazyInitializationException: illegal access to loading collection"

I've tried other solutions for this problem posted here but nothing is working. Whats really odd is if I insert the following code just before I try to access the account then everything works:

var acc = from a in _accountRepository.GetAll()
                  where a.Customer.Equals(customer)
                  select a;

All I've done in the preceding code is create a variable that I don't even use. Somehow it causes the statement "Account account = customer.Accounts.FirstOrDefault();" to succeed though.

Anyone have any ideas what's going on here?

Wim Coenen
  • 66,094
  • 13
  • 157
  • 251
JMc
  • 971
  • 2
  • 17
  • 26

3 Answers3

4

I think it's quite simple: you no longer have an open ISession associated to the entity. And, I think that this is due because leave your session-management (open / close session) as a responsability to the Repository, and that's wrong.

Frederik Gheysels
  • 56,135
  • 11
  • 101
  • 154
  • Opening and closing the session is handled by a separate unit of work class. The same unit of work is then passed to all repositories so they are associated with the same unit of work. I don't leave this responsibility to the repositories themselves. – JMc Apr 01 '11 at 11:52
0

The problem here was in fact that the 'ISession' was closed, although this was not because of it being handled by individual repositories as previously suggested.

The cause of the issue was that I declared my UnitOfWork (ISession) outside of the scope of my business method - PlaceOrder(). For example:

ISession myUnitOfWork = new ISession();


public void PlaceOrder()
{

    var myRepository = new IRepository<Customer>(myUnitOfWork);
    ....
    ....
    Commit();
}

So the first call to the PlaceOrder() method was fine, but on additional calls the ISession had been closed, hence the "Illegal Access to loading collection" message. The solution was to declare the ISession within the PlaceOrder() method:

public void PlaceOrder()
{
    ISession myUnitOfWork = new ISession();
    var myRepository = new IRepository<Customer>(myUnitOfWork);
    ....                

Ultimately this issue was the result of a lack of understanding of the the concept of a Unit of Work. If my understanding is now correct, then each business method (such as PlaceOrder above) is a new transaction and therefore requires an ISession to be opened at the start and closed at the end. I was declaring the ISession outside the scope of the method thinking that it only needed to be declared once.

JMc
  • 971
  • 2
  • 17
  • 26
  • The answer is written 2 years ago, so by this time, you would be good at this concept, but ISession is usually injected into repository class' constructor via IoC container like Ninject or Castle Windsor to utilise the benefit of UoW. IRepository is injected as well into your business class' constructor, so you don't have to open ISession at beginning and close it at the end. – Andrew Chaa Nov 08 '13 at 16:08
0

I was also getting this error - but I only noticed it at a break point. My error was caused by having the DebuggerDisplay attribute trying to show properties that were being loaded lazily.

David
  • 1