NHibernate Lazy loading and JSON

Share on:

När man arbetar med NHibernate mot databas så är lazy-loading aktiverat per default.

var session = sessionFactory.OpenSession();
var users = session.Query<User>()
	.ToList();

Denna query hämtar Users-tabellen och ingenting annat. Trots att man gjort ToList() är inte kopplingen mot sessionen bruten, så går man ner i users-objektet så finns relationerna där så länge sessionen är öppen.

var roles = users.Roles.ToList(); //fungerar!

Notera att i ovan fall så sker det då flera frågor mot databasen, eftersom att i första läget hämtas bara Users-tabellen, och sen när man väl punktar ner till en relation görs det nya frågor. Vet man med sig att man vill arbeta på relationerna så kan man göra en eager load, och ta med dem i samma SQL-fråga mot databasen med Fetch():

var session = sessionFactory.OpenSession();
var users = session.Query<User>()
	.Fetch(u => u.Roles)
	.ToList();

Problemet är när man vill returnera users från en Controller med t ex Json, då serialiseringen traverserar de properties som finns och därmed gör ytterligare slagningar mot databasen. Ett litet objekt med många relationer kan bli hur stort som helst och ge många onödiga slagningar mot DB.

En lösning är att använda en StatelessSession istället för en vanlig Session. Den gör att objektet inte har någon koppling till sessionen efter en ToList().

var session = sessionFactory.OpenStatelessSession();
var users = session.Query<User>()
	.ToList();

Här gäller det dock att notera att man inte kan jobba vidare på objektet och spara tillbaka det i sessionen. Det här blir alltså endast en read-onlyvy.

Även om Stateless-sättet fungerar så är det rekommenderade för att leverera data från server till klient att skapa domänobjekt som man returnerar från Controllern med JSON, så man har full kontroll över vad som skickas över till klienten. Alltså antingen returnera ett anonymt otypat objekt, eller skapa en ny klass som man populerar med de värden vi behöver för klienten.