Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
Considering a View's Get/Set Roles with MVP

[Update May 7, 2007:  Added sequence diagram, submitted by Yanic Inghelbrecht, to better explain "Use Update Method in lieu of Getter" technique.]

There are many ways to implement Model-View-Presenter; Supervising Controller and Passive View are just two implementation examples.  A question was asked on my overview of the subject as to whether or not a view's properties should have both setters and getters.  For example, consider an "add/edit customer" view.  This view first shows the available customer data, via a setter on the view, and then allows the user to update the information displayed.  Should the view have both a setter and a getter for the customer class?  (As I understand it, if you're using Passive View, this is a moot question as the view should not be intelligent enough to interpret and/or update the domain model directly.)  But if you're using Supervising Controller or another approach which allows the view to know about the domain model (or DTOs for the domain model) then this is a great question to discuss.  I'll list the (un)successful approaches I've used and pros/cons of each.  (Here, I use "entity" to mean any domain object that's stored within the DB.)

Return Ready-to-Save Entity from View via Getter
With NHibernate, if you have a ready-for-storage entity, you may simply call SaveOrUpdate on that object.  If a new entity is being created, then the view may need to work with factories and/or be aware of the business rules for creating a ready-to-save entity.  The internal consistency of that object can, obviously, be verified by the presenter or validation logic built into the domain object itself, but I never liked this approach as it gives the view a lot of responsibility for creating a new entity and creates a lot of untestable code.

If an existing entity is simply being updated and returned via the getter, the view must have a handle on the existing entity to update it.  Accordingly, the view can:

  1. Re-create the entity from scratch, set its ID accordingly, and return the ready-to-save object.  This approach is wrought with problems.  If the view gives the recreated object a wrong ID, you've now corrupted your data.  In my overview of NHibernate, I exposed ID as a publicly, settable property.  In my upcoming update to this article, I recommend not exposing the ID setter.  Only the ORM or entity-loader should be able to set this critical property.  As another drawback, if the entity keeps track of auditing information, such as DateCreated, this approach will overwrite it.  There are other drawbacks to this approach and it should be avoided.
  2. The view can talk to a DAO directly to get the existing entity, update it's properties, and return it to the view.  Although not as bug-prone as the previous suggestion, this now gives the view the responsibility of coordinating with the data-access layer directly.  This grays the line between the responsibilities of the view and the other layers of the application and adds non-trivial business logic to the view which is difficult to test.
  3. The view can be given a direct handle to the loaded entity by the presenter via another setter.  This seems a bit round-about and depends on a two-step process.  Additionally, the view now has two setters which may be confusing and difficult to maintain.

Return DTO from Getter
Instead of returning a fully ready-to-save object from the view, the view could, alternatively return a DTO consisting of only the appropriate information to be updated.  The presenter could, in turn, get the existing object from the DB (or create a new one), transfer the DTO information onto the persistent object, and save it back to the DB.  The primary benefit is that you can completely separate the view from knowing anything about the domain model while still being able to communicate more than one primitive at a time.  The major drawback is that DTOs now need to be maintained along with their domain model pairs.  So if you add a new, updateable property to the domain object, you'll then need to add the property to the DTO and then modify the DTO-to-domain-object transfer logic within the presenter.  (Alternatively, You could also add an UpdateWith(DTO) to the entity so that the transfer logic is more contained, but it still leads to further maintenance.)  But the bottom line is that this is a good approach if you really need to keep your views from having a direct dependency on the domain layer.  Because of this clean separation, this brings the added benefit of removing temptation for domain logic to bleed into views since the view is limited to communicating with the Presenters/DTO layer.  But again, it comes with a lot of additional maintenance to keep the DTOs synched with the domain model.

Use Update Method in lieu of Getter
A simpler approach that I'm having luck with is including a separate update method on the view and not having a getter for the entity.  Going back to the "add/edit customer" example, a "Customer { set; }" would be on the view interface to show the data, but not a getter.  The view interface would then also include a "void Update(Customer customer);" method.  Accordingly, the view would then accept a customer object from the presenter and update its properties from the view.  The communications would be as follows:

The above image was created and submitted by Yanic Inghelbrecht via Trace Modeler.  Thanks Yanic!

The sequence diagram is interpreted as follows:

  1. User clicks "Save Changes" button which invokes btnSaveChanged_OnClick in the code-behind.
  2. Code-behind calls presenter.SaveChangesTo(customerId).
  3. Presenter talks to the Customer DAO (or service layer) to get the loaded entity from the DB, using the ID passed to it from the view.  (If the ID was 0, then the Presenter creates a new entity via a constructor or factory.)
  4. Presenter calls view.Update(customerToBeSaved), passing the entity loaded from the DB.
  5. View updates the entity with values from a form.
  6. (Optionally, when appropriate) Presenter, or more appropriately, the domain layer via something like the Validation Application Block, verifies that the updated entity is internally valid.
  7. Presenter calls customerDao.SaveOrUpdate(customerToBeSaved).

With this approach, the view remains ignorant between whether a new entity is being created or an existing one is being updated.  Furthermore, separate DTOs aren't being maintained while still minimizing the responsibilities of the view.  As an added bonus, there's very little code that's not testable.  The drawback to this is that it gives the view direct access to the persisted objects and, thus, the domain layer itself.

A Place for View Getters
There are other scenarios in which getters on the view are valuable.  One such example is an IsDefaultView/IsPostBack getter so that the Presenter can determine if post-back-specific actions are necessary.  But in my own experiences, I usually pass contextual data, such as this, into the InitView, or other method, of the Presenter.  But at times, exposing a getter on the view can be simple and useful.

Recommendations
If your project (team) requires a very clean separation between the view and domain layer, then I recommend considering the "Return DTO from Getter" approach.  This keeps the view very contained while allowing you to be more efficient than passing around a ton of primitives.  But like CRUD stored procs, the DTOs require a lot of maintenance.  Alternatively, if you have a smaller and/or more experienced team, you can bypass the DTO layer altogether in favor of the "Use Update Method in lieu of Getter" approach.  This is simple, minimizes responsibilities of the view but, on the downside, allows the view to do more damage, so to speak.  But with proper encapsulation, the view's access to the domain layer can still be limited.  I've been developing/maintaining my current project for 1 1/2 years and have found the latter approach to be the most maintainable and simple.  But either way, both approaches lead to highly testable code.

Billy McCafferty


Posted 03-19-2007 9:40 AM by Billy McCafferty
Filed under:

[Advertisement]

Comments

Thomas Eyde wrote re: Considering a View's Get/Set Roles with MVP
on 03-19-2007 3:49 PM

"Use Update Method in lieu of Getter" sounds like music in my ears :)

I am currently trying out my variation of Presenter First, and tomorrow seems like the day where I have to do my first update. The Update Method is exactly what I have in mind.

JoeyDotNet wrote re: Considering a View's Get/Set Roles with MVP
on 03-20-2007 9:17 AM

Great Stuff!  Speaking as one who's dealt with the pain of maintaining DTO-to-Entity mapping, I can attest that it can definitely be overkill for fairly trivial CRUD apps.  I do usually prefer Passive View, but I really like your use of an update method on the view.

rajiv wrote re: Considering a View's Get/Set Roles with MVP
on 03-23-2007 2:33 AM

Thanks for the reply! I posted a connected question in the code project forum.

Joey Chömpff wrote re: Considering a View's Get/Set Roles with MVP
on 04-20-2007 3:52 AM

Hey great article. I'm using the Web Client Software Factory for some time now and this uses an ObjectContainerDatasource who redirects events (CUD) to the presenter.

Billy McCafferty wrote re: Considering a View's Get/Set Roles with MVP
on 04-20-2007 12:54 PM

Joey,

Do you have any major complaints of WCSF at all?  I haven't tried it myself yet but want to give it a shot.

Joey Chömpff wrote re: Considering a View's Get/Set Roles with MVP
on 04-25-2007 7:27 AM

No I don't have major complaints about it, but there aren't many examples on this framework. And I'm quite new at the IoC principle.

Doctor Deploys Blog :: Model View Presenter links wrote Doctor Deploys Blog :: Model View Presenter links
on 11-06-2007 1:52 PM

Pingback from  Doctor Deploys Blog  ::     Model View Presenter links

How loose is loose enough? « maonet technotes wrote How loose is loose enough? « maonet technotes
on 11-06-2007 10:27 PM

Pingback from  How loose is loose enough? « maonet technotes

MVP (Model-View-Presenter) « Eppur si muove wrote MVP (Model-View-Presenter) « Eppur si muove
on 11-28-2007 8:26 AM

Pingback from  MVP (Model-View-Presenter) « Eppur si muove

dave^2=-1 wrote Considering a View's Get/Set Roles with MVP
on 02-01-2008 5:54 AM

Billy McCafferty has a nice post titled Considering a View's Get/Set Roles with MVP . Billy looks at

Rüya Tabirleri wrote re: Considering a View's Get/Set Roles with MVP
on 09-01-2010 2:55 PM

Thank you comment

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)