NHibernate, skillnader mellan Load, Get och Criteria

Posted by Kenny Eliasson | Posted in , , , , , , | Posted on 08:56

Stötte på ett konstigt problem häromdagen när jag satt och refaktorerade data-access kod via NHibernate till ett av de första projekten där vi använde det. Problemet som skulle lösas var att ConnectionStrings var hårdkodade i vårt hemgjorda assembly.

För att lösa problemet använde jag kod från ett nyare projekt.

I projekten har vi ett Bas-repository som vi använder oss utav och när jag satt och kikade på skillnaderna såg att GetById() metoden skiljde sig åt i de båda klasserna.

I den gamla klassen anropades Session.CreateCriteria() istället för det Load() eller Get() som man kanske hade kunnat förutspå.

Skillnaderna mellan Criteria, Get och Load som jag fattat det är att


  • Load()
    Hämtar aldrig ifrån databasen utan returnerar bara en proxy. Det vill säga, använder du Load() med ett ID som inte finns i databasen kommer du inte få ett fel förrens du försöker komma åt objektets egenskaper. Denna lösningen är den att rekommendera när du vill koppla på referenser till t.ex. nya skapade objekt men inte vill ladda upp alla dessa referenser bara för att kunna spara det nya objektet.

  • Get
    Samma som Load() men kommer att gå till databasen/cachen för att veta att ID:et verkligen finns.

  • CreateCriteria
    CreateCriteria är lite svårare, kommer man ifrån en värld där man är van att skriva Sql själv så tänker man ju förstås att det måste vara den korrekta vägen att gå. Men CreateCriteria hoppar över cachen (om inte specifierat annorlunda) och objektet man får tillbaka cachas inte.

  • Källa
    Läs mer här Ayende om Load, Get och Query By Id


Jag tänkte inte särskilt mycket mer på att vi använde CreateCriteria utan bytte helt sonika ut den mot en Load. Efter mycket pill så hade jag lyckats byta ut den gamla implementation mot den nya.

Tryckte på F5 och körde igång projektet. Och till min stora förvåning funkade allt perfekt, ett tag iallafall. Helt plötsligt fick jag ett exception ifrån NHibernate.

(No persister exists for QS.Product.Core.Interfaces.ICustomer)

Nu tänker man såklart, detta kanske har med att jag glömt embedda en mapping fil, men si, så lätt var det inte. Jag gick till mappningen och kollade, såg att vi mappade till klassen som interfacet implementerade och använde interfacet som proxy-klass.

Koden i som kastade felet såg ut så här:

_session.Load<ICustomer>(531);

Med tanke på felmeddelandet så måste ju detta betyda att ICustomer inte var mappad, vilket den ju inte heller var, det var ju implementation av Interfacet som var mappat. Men hur kunde det funkat innan? Jag bytte ju bara ut bas-repositoriet, inte alla repositoryn som användes, inte heller ändrade jag configuration eller mappningen.

Problemet låg i att CreateCriteria() kan hantera detta, varför, det vet jag inte :)

Men lösningen för mig var att typa om alla mina repositories till att använda klassen istället för interfacet.

Det vore intressant att veta varför CreateCriteria funkar men inte Load/Get :)

Detta blev ett långt första inlägg, får hålla mig lite kortare i framtiden.