I have seen numerous examples of lazy loading - what's your choice?
Given a model class for example:
public class Person
{
private IList<Child> _children;
public IList<Child> Children
{
get {
if (_children == null)
LoadChildren();
return _children;
}
}
}
The Person class should not know anything about how it's children are loaded .... or should it? Surely it should control when properties are populated, or not?
Would you have a repository that couples a Person together with its children collection or would you use a different approach, such as using a lazyload class - even then, I don't want a lazyload class blurring in my model architecture.
How would you handle performance if first requesting a Person and then its Children (i.e. not lazy loading in this instance) or somehow lazy loading.
Does all this boil down to personal choice?
The best lazy loading is avoiding it ;) Thread safety is an immediate problem you'll have to handle. I have no count of how often I have seen production systems with 8 cpu cores run lazy loading 8 times for every single lazy loading pattern in use. At least on server startups all server cores have a tendency to end up in the same places.
Let a DI framework construct it for you instead, if you can. And if you cannot, I still prefer explicit construction. So all sorts of AOP magic simply do not cut it with me, go for explicit construction outside the class. Don't put it inside the person class, just make a service that constructs the objects in the proper manner.
Introducing "magic" layers that more or less transparently do these things seem like a nice idea, but I have yet to come across implementations that do not have unforseen and problematic consequences.
You can use the Lazy<T>
class I talked about here :
What is the proper way to inject a data access dependency for lazy loading?
There is also link to a more detailed blog post there...
I talked about a solution I use to accomplish lazy loading here
You can use the Virtual Proxy pattern, along with the Observer pattern. This would give you lazy loading without the Person class having explicit knowledge about how Children are loaded.
I'm thinking that this is precisely the kind of problem that is best handled by AOP (e.g., PostSharp). Have your lazy loading as an aspect and then use it to decorate whatever property you want to be loaded lazily. Disclaimer: haven't tried it; just thinking that it should work.
I just asked a related question here, but it was heavier on the Immutability & Thread Safety tack. Lots of good answers and comments. You may find it useful.
Here is an example implementing lazy loading using the Proxy pattern
The Person class that would live with the rest of your models. Children is marked as virtual so it can be overridden inside the PersonProxy class.
public class Person {
public int Id;
public virtual IList<Child> Children { get; set; }
}
The PersonRepository class that would live with the rest of your repositories. I included the method to get the children in this class but you could have it in a ChildRepository class if you wanted.
public class PersonRepository {
public Person FindById(int id) {
// Notice we are creating PersonProxy and not Person
Person person = new PersonProxy();
// Set person properties based on data from the database
return person;
}
public IList<Child> GetChildrenForPerson(int personId) {
// Return your list of children from the database
}
}
The PersonProxy class that lives with your repositories. This inherits from Person and will do the lazy loading. You could also use a boolean to check if it has already been loaded instead of checking to see if Children == null.
public class PersonProxy : Person {
private PersonRepository _personRepository = new PersonRepository();
public override IList<Child> Children {
get {
if (base.Children == null)
base.Children = _personRepository.GetChildrenForPerson(this.Id);
return base.Children;
}
set { base.Children = value; }
}
}
You could use it like so
Person person = new PersonRepository().FindById(1);
Console.WriteLine(person.Children.Count);
Of course you could have PersonProxy take in an interface to the PersonRepository and access it all through a service if you don't want to call the PersonRepository directly.