A guide into OR/M implementation challengesLazy loading
Continuing to shadow Davy’s series about building your own DAL, this post is about the Lazy Loading. Davy support lazy loading is something that I had great fun reading, it is simple, elegant and beautiful to read.
I don’t have much to say about the actual implementation, NHibernate does things in much the same way (we can quibble about minor details such as who holds the identifier and other stuff, but they aren’t really important). A major difference between Davy’s lazy loading approach and NHibernate’s is that Davy doesn’t support inheritance. Inheritance and lazy loading plays some nasty games with NHibernate implementation of lazy loaded entities.
While Davy can get away with loading the values into the same proxy object that he is using, NHibernate must load them into a separate object. Why is that? Let us say that we have a many to one association from AnimalLover to Animal. That association is lazy loaded, so we put a AnimalProxy (which inherit from Animal) as the value in the Animal property. Now, when we want to load the Animal property, NHibernate has to load the entity, at that point, it discovers that the entity isn’t actually an Animal, but a Dog.
Obviously, you cannot load a Dog into an AnimalProxy. What NHibernate does in this case is load the entity into another object (a Dog instance) and once that instance is loaded, direct all methods calls to the new instance. It sounds complicated, but it is actually quite elegant and transparent from the user perspective.
More posts in "A guide into OR/M implementation challenges" series:
- (28 Aug 2009) Custom Queries
- (28 Aug 2009) Lazy loading
- (27 Aug 2009) The Session Level Cache
- (26 Aug 2009) Hydrating Entities
- (25 Aug 2009) CRUD
- (24 Aug 2009) Mapping
- (24 Aug 2009) Reasoning
Comments
And best of all, the NHibernate approach makes you work harder to eliminate down-casting in your design :)
So...this means that if someone has a direct reference to the Dog, doing an instance equality comparison between that Dog and the object returned by the Animal property will fail?
And downcasting is reality for a lot of aspect code, while I know why we should strive to avoid downcasting code and use polymorphism instead whenever possible, it is not always practical...so making that more cumbersome can hardly be thought of as a benefit, right? :-P
Mats,
instance references comparisons would fail, yes. That is why NH says that entities SHOULD provide Equals impl.
It is also called the leaking this issue.
As for downcasting, there are ways to get the actual unproxied instance, you just need to be aware of that. But I don't see why you need downcasting in aspect code.
"That is why NH says that entities SHOULD provide Equals impl."
Ah, right - forgot about that!
"But I don't see why you need downcasting in aspect code"
well, an example could be an aspect that presents something, say a Product, as Html and that in the presentation method goes on to try to downcast the product to a few known subtypes, such as Book and DVD, to present particular information about these. Standard OO might suggest that using polymorphism would be the way to go for this type of thing, but OTOH at some point overloading objects with too many responsibilities is a problem of its own. Mapping to a presentation model is a possibility, but using aspects and a little downcasting can be another, admittedly not as clean, but sometimes more practical solution. Especially if it is easier to come over a good AOP framework than a good O/O Mapping framework to map between the presentation model and the domain model.
Mats,
Oh, in that case, you don't have to worry about this at all.
NH manages proxy instances in a different manner. You just use the Interceptor.Instansiate to make sure that you give NH an instance with the right proxy, and there are no issues there.
Comment preview