views:

415

answers:

7

I have a simply Class that is intended to be a simple POCO - it just holds data. With one exception: It contains a Collection of Notes. I want to lazy-load this collection so that I don't have to fetch the Notes on Pages that don't need them. The stub for this is this:

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'm wondering how to proceed from here. It's an ASP.net MVC application and I use Dependency Injection to inject the IRepositories in classes that need them, for example my controllers. But as this class here is supposed to be a really simple DTO, I'm reluctant to inject an INoteRepository into it, also because the caller shouldn't worry or care about the fact that this is lazy-loaded.

So I'm thinking of having another Class in my Model that holds a 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 would work of course, but I wonder if this is the correct architecture? I couple the simple DTOClass to another Data Access class and possibly also to my DI mechanism (as I need to create an Instance of the Data Access class in the getter of Notes).

Would you do it differently? Is there a better way to do this, also keeping in mind I already use Ninject?

I'm guessing that this is not a POCO or DTO anymore as it now contains logic, but that's okay. I want it to appear like a POCO to outside caller so I like to have a Property "Notes" rather than methods like "GetNotesForProject" on this or other classes.

My current solution is really ugly, as I need to get the Ninject Kernel from my MvcApplication and use it to spin up the ProjectDataProvider class which takes an INoteRepository in it's constructor, 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: Opened a bounty. Let's ignore the terminology of "POCO" and "DTO", I'll refactor accordingly. So this is about: How should the Lazy-Loading code look in such a situation, and can/should I avoid passing INoteRepository into the MyDTOClass?

+2  A: 

You're defeating the whole purpose of DTOs when you try to add lazy-loading logic to it. I think, you should have two separate objects: one with Notes, and another -- without them.

Anton Gogolev
Possibly, but I'm not sure if I want to fracture it. Would you recommend having MyDTOClass without the Notes and then subclassing it as MyDTOClassWithNotes : MyDTOClass which adds the notes (ignore the bad Naming)? I could still pass in the WithNotes class into functions that only expect MyDTOClass. I just don't know if there's anything against it, apart of course from having an additional class.
Michael Stum
I agree with Anton. Your DTO should reflect exactly what the view needs. If it needs the notes, the DTO should contain the notes. If the view needs the notes lazy-loaded, then provide the view with a DTO without the notes, and provide a mechanism for the view (a partial view?) to do the lazy loading of its own notes for a given class using a controller designed to do just that. This keeps the Domain classes, the DTOs, the controllers, and the views pure and simple.
Eric King
+7  A: 

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

dtoland
Awesome! Sadly I can't wait for this project, but I'll definitely keep that in mind.
Michael Stum
A: 

You could have the Notes property take in an INoteRepository as a parameter. That way the calling code could pass in the correct instance of INoteRepository.

Kevin Pang
That would make it a method though, and I'd like the consumer of MyDTOClass not knowing/caring about this - it should be transparent. Otherwise I would possibly move it out of the class completely.
Michael Stum
My fault, I've been working in VB.NET lately which allows passing parameters into properties and forgot that C# doesn't support this. :-(
Kevin Pang
+1  A: 

After having roamed the astral realms for aeons in desperate search for an answer, I have come to the final conclusion that yes, it's unnecessary to pass a repository into your entity instance, because a repository for an entity type should always be a singleton.

So you could write in your entity class simply 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;
        }
    }
}

This really solved all headaches for me.

The repository must be implemented in a way that it would always know what to do with the data.

Remember that one repository implementation would for example get the data from the database, while another might get it from a web service. Because of the loose coupling, the repository implementation module is easily replaceable and any data communication is even arbitrarily chainable.

If you have a scenario where you would say "but the repository can't be singleton because I have a complex scenario where I for example access more than one data source and it depends on the actual Monster instance where to get the Victims from", then I say well you must create a repository implementation which knows all data sources and keeps track of where the entity instances come from and where they will go, and so on...

If you feel this approach is not POCO enough, then you must create another loosely coupled Business Logic Layer which wraps or derives from the POCO entity and implements the repository interaction there.

I hope I could give a hint into a direction that feels right for you and anyone. I actually do believe this is the holy grail for multilayer/-tier development. Feel free to further discuss.

herzmeister der welten
I was thinking about something like that, the problem is just that I don't know the name of the class that implements the repository as it's created through Dependency Injection. But I'm guessing I need a static Factory class...
Michael Stum
Yap there are surely more ways to do it. I used to fiddle around with IMonsterRepository and factory and stuff as well but after all, if it's singleton anyway, I only need an abstract base class for the repository. The static Instance property would call a Resolver that knows how to create an instance for a repository and then cache it.
herzmeister der welten
+6  A: 

Your DTO doesn't need to know about the repository itself. All it needs is a delegate that can provide it with the value for 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 is supposed to provide you with an instance of the DTO, we should be able to pass in the value provider delegate like so:

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?

LightX
This is the best answer IMO, it provides the solution and does not inherently make his DTO class dependent on an IRepository, I pretty sure I've seen this pattern implemented in a reusable way either as ILazy<T> or AbstractLazy<T>.
Chris Marisic
Ya.. I think this is exactly what Lazy<T> in .net 4 do.
LightX
Yes, this is the method I would use as well. Functional programming 4tw. =)
Erik Forbes
That's a cool approach, I'll play around with that. The main point is indeed that I can completely decouple this from the INoteRepository
Michael Stum
Several really good options here, but I went with this one because it worked best in _my_ Application.
Michael Stum
Amazingly elegant solution. Another reason to use .net 
Cherian
+2  A: 

Another option is to use proxies that inherit from the objects you want to retrieve (following the lead of some object-relational mappers, like NHibernate).

This provides a degree of persistence ignorance by keeping the data access code separate 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 its return type but returns the lazy object instead:

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

MyDTOClass consumers don't need to know they're dealing with proxies, nor do they have to interact with repositories (except for whatever class makes the initial call of course).

Jeff Sternal
Interesting Idea. Even the initial caller could possibly decoupled by giving the knowledge about the INoteRepository to the MyDTOClassRepository (Maybe Factory is a better term) class. Have to experiment with that a bit.
Michael Stum
+1  A: 

You can't achieve independence from your repository if you're lazy loading from it. You can keep it at arm's length by using a callback or proxy or letting NHibernate do the dirty work for you, but your DTO has to access the repository to load the Notes.

Your main goal appears to be "I want it to appear like a POCO to outside caller so I like to have a Property "Notes" rather than methods like "GetNotesForProject" on this or other classes." Can't you accomplish this with ninject and constructor injection? Once you've set up ninject you can call kernel.Get() to get a new instance that will not expose any reference to your repository.

Jamie Ide
Yes, that's what I am doing right now, but as you see above, there is no really convenient way to access the Kernel as it sits in the MvcApplication. I've opened the question to see what the best approach would be: Move the Kernel into static class to make it globally available, or somehow de-couple the Application enough that my "DTO" doesn't need the kernel or a Repository passed in.
Michael Stum