Lazy Loading Collection - how to get items?

I just have a class that is designed for simple POCO - it just stores data. With one exception: contains a collection of notes. I want to download this collection so that I donโ€™t have to retrieve Notes on pages that they donโ€™t need. To do this, do the following:

public class MyDTOClass { private ICollection<Note> _notes = null; public ICollection<Note> Notes { get { if(_notes == null) { // Get an INoteRepository and initialize the collection } return _notes; } } } 

Now I wonder how to get out of here. This is an ASP.net MVC application, and I use Injection Dependency to inject IRepositories into the classes they need, like my controllers. But since this class should really be a simple DTO here, I donโ€™t want to inject INoteRepository into it, also because the caller does not have to worry or worry about being lazy.

So, I think that in my model there is another class that contains an INoteRepository.

 public class MyDataAccessClass { private INoteRepository _noteRepo; // Inject is part of Ninject and makes sure I pass the correct // INoteRepository automatically [Inject] public MyDataAccessClass(INoteRepository noteRepository) { _noteRepo = noteRepository; } public IEnumerable<Note> GetNotes(int projectId) { return _noteRepo.GetNotes(projectId); } } 

This will work, of course, but I wonder if this architecture is correct? I am connecting a simple DTOClass to another data access class and possibly also to my DI mechanism (since I need to instantiate the data access class in getter Notes).

Would you do it differently? Is there a better way to do this, also bearing in mind that I'm already using Ninject?

I guess this is not POCO or DTO anymore, as it now contains logic, but it is good. I want it to appear as POCO for the external caller, so I like to have the Notes property, not methods like GetNotesForProject in this or other classes.

My current solution is really ugly, since I need to get Ninject Kernel from my MvcApplication and use it to deploy the ProjectDataProvider class, which uses the INoteRepository constructor in it to avoid having to put the INoteRepository somewhere in my "DTO" class:

 public ICollection<Note> Notes { get { if(_notes == null) { var app = HttpContext.Current.ApplicationInstance as MvcApplication; if (app == null) throw new InvalidOperationException("Application couldn't be found"); var pdp = app.Kernel.Get<ProjectDataProvider>(); _notes = new List<Note>(pdp.GetNotes(Id)); } return _notes; } } 

Edit: Open generosity. Let the terminology โ€œPOCOโ€ and โ€œDTOโ€ be ignored, I will reorganize accordingly. So, here's what: what should the Lazy-Loading code look like in this situation, and can / should I avoid passing INoteRepository to MyDTOClass?

+7
architecture ninject
source share
7 answers

Your DTO should not know about the repository itself. All he needs is a delegate who can provide him with meaning for the notes.

How about something like this:

 public class MyDTOClass { private ICollection<Note> _notes = null; public ICollection<Note> Notes { get { if (_notes == null) { if (notesValueProvider == null) throw new InvalidOperationException("ValueProvider for notes is invalid"); _notes = notesValueProvider(); } return _notes; } } private Func<ICollection<Note>> notesValueProvider = null; public MyDTOClass(Func<ICollection<Note>> valueProvider) { notesValueProvider = valueProvider; } } 

Since, by definition, your repository should provide you with a DTO instance, we should be able to pass the value provider delegate like this:

 public class Repository { public MyDTOClass GetData() { MyDTOClass dto = new MyDTOClass(FetchNotes); return dto; } public ICollection<Note> FetchNotes() { return new List<Note>(200); } } 

Will this work for you?

+8
source share

If you can wait for .Net 4 (i.e. not yet in production) Lazy (of T) is the new Lazy Loading feature in the .NET framework. http://msdn.microsoft.com/en-us/library/dd642331(VS.100).aspx

+7
source share

You lose the DTO goals when you try to add lazy loading logic to it. I think you should have two separate objects: one with Note s, and the other without them.

+2
source share

Another option is to use proxies that inherit the objects you want to receive (following the example of some object-relational maps, such as NHibernate).

This provides a degree of uncertainty by storing the data access code separately from the domain model:

 public class MyLazyDTOClass: MyDTOClass { // Injected into the constructor by the MyDtoClass repository private INoteRepository noteRepository; public ICollection<Note> Notes { get { if(base.Notes == null) { base.Notes = noteRepository.GetNotes(projectId); } return base.Notes; } } } 

MyDTOClassRepository declares the base object as a return type, but instead returns a lazy object:

 public MyDTOClassRepository { public MyDTOClass GetMyDTOClass(int id) { // ... Execute data access code to obtain state ... return new MyLazyDTOClass(this, state); } } 

MyDTOClass consumers do not need to know that they are dealing with proxies, and they do not need to interact with repositories (except that any class makes the initial call, of course).

+2
source share

After I cast astral spheres for eons in a desperate search for an answer, I came to the final conclusion that yes, there is no need to transfer the repository to my instance of the object, since the repository for an entity type should always be singleton.

So, you can write in your entity class just something like:

 public class Monster { public ReadOnlyCollection<Victim> _victims; public ReadOnlyCollection<Victim> Victims { get { if (this._victims == null) // Note: Thread-Safety left out for brevity { this._victims = VictimRepository.Instance.GetVictimsForMonster(this); } return this._victims; } } } 

It really solved all the headaches for me.

The repository should be implemented in such a way that it always knows what to do with the data.

Remember that one repository implementation could, for example, retrieve data from a database, and another could retrieve it from a web service. Due to the weakened connection, the repository implementation module is easily replaced, and any data transfer is even arbitrarily connected.

If you have a scenario where you would say "but the repository cannot be single-point because I have a complex scenario where I, for example, access multiple data sources, and this depends on the actual Monster instance where you can get Victim from" , then I say well that you must create a repository that knows all the data sources and tracks where the entity instances come from and where they will go, and so on ...

If you think that this approach is not enough POCO, you should create another loosely coupled business logic level that wraps or inferred from the POCO object and implements interaction with the repository there.

I hope I could give a hint in a direction that seems right for you and for anyone. I truly believe that this is the holy grail for multi-layered development. Feel free to discuss.

+1
source share

You cannot achieve independence from your repository if it is lazy loading. You can keep it at hand with a callback or proxy, or let NHibernate do the dirty work for you, but your DTO needs to access the repository to download Notes.

Your main goal seems to be "I want it to appear as POCO for the external caller, so I like to have the" Notes "property, not methods like" GetNotesForProject "in this or another class." Can't you accomplish this with ninject and constructor injections? After you have configured ninject, you can call kernel.Get () to get a new instance that will not reference your repository.

+1
source share

You can use the Notes property in INoteRepository as a parameter. Thus, the calling code may pass in the correct instance of INoteRepository.

0
source share

All Articles