R – How to handle view model with multiple aggregate roots

asp.net-mvcautomapperviewmodel

At the moment, i got quite badly fashioned view model.

Classes looks like this=>

 public class AccountActionsForm
    {
        public Reader Reader { get; set; }
        //something...
    }

Problem is that Reader type comes from domain model (violation of SRP).

Basically, i'm looking for design tips (i.e. is it a good idea to split view model to inputs/outputs?) how to make my view model friction-less and developer friendly (i.e. – mapping should work automatically using controller base class)?

I'm aware of AutoMapper framework and i'm likely going to use it.

So, once more – what are common gotchas when trying to create proper view model? How to structure it? How mapping is done when there's a multiple domain object input necessary?


I'm confused about cases when view needs data from more than 1 aggregate root. I'm creating app which has entities like Library, Reader, BibliographicRecord etc.

In my case – at domain level, it makes no sense to group all those 3 types into LibraryReaderThatHasOrderedSomeBooks or whatnot, but view that should display list about ordered books for specific reader in specific library needs them all.

So – it seems fine to create view OrderedBooksList with OrderedBooksListModel view model underneath that holds LibraryOutput, ReaderOutput and BibliographicRecordOutput view models. Or even better – OrderedBooksListModel view model, that leverages flattening technique and has props like ReaderFirstName, LibraryName etc.

But that leads to mapping problems because there are more than one input.
It's not 1:1 relation anymore where i kick in one aggregate root only.
Does that mean my domain model is kind a wrong?

And what about view model fields that live purely on UI layer (i.e. enum that indicates checked tab)?

Is this what everyone does in such a cases?

 FooBarViewData fbvd = new FooBarViewData();
   fbvd.Foo = new Foo(){ A = "aaa"};
   fbvd.Bar = new Bar(){ B = "bbb"};
   return View(fbvd);

I'm not willing to do this=>

var fbvd = new FooBarViewData();
   fbvd.FooOutput =  _mapper.Map<Foo,FooOutput>(new Foo(){ A = "aaa"});
   fbvd.BarOutput = _mapper.Map<Bar,BarOutput>(new Bar(){ B = "bbb"});
   return View(fbvd);

Seems like a lot of writing. 🙂


Reading this at the moment. And this.


Ok. I thought about this issue a lot and yeah – adding another abstraction layer seems like a solution =>

alt text

So – in my mind this already works, now it's time for some toying.

ty Jimmy

Best Answer

It's tough to define all these, but here goes. We like to separate out what we call what the View sees from what the Controller builds. The View sees a flattened, brain-dead DTO-like object. We call this a View Model.

On the Controller side, we build up a rich graph of what's needed to build the View Model. This could be just a single aggregate root, or it could be a composition of several aggregate roots. All of these together combine into what we call the Presentation Model. Sometimes the Presentation Model is just our Persistence (Domain) Model, but sometimes it's a new object altogether. However, what we've found in practice is that if we need to build a composite Presentation Model, it tends to become a magnet for related behavior.

In your example, I'd create a ViewFooBarModel, and a ViewFooBarViewModel (or ViewFooBarModelDto). I can then talk about ViewFooBarModel in my controller, and then rely on mapping to flatten out what I need from this intermediate model with AutoMapper.