Mapping and Wrapping


By Mats Helander

With the aid of O/R Mapping, we are able to connect our Domain Model to the relational database. Together with the business methods that we add to the Domain Model classes and possibly to a Service Layer [Fowler PoEAA], we have a pretty solid architecture in place for the structural and functional foundation of the application.

That brings us to the last stretchthe Presentation Layer (PL). While you and I may consider the Domain Model to be the heart of the application, end users are likely to think of whatever they are presented with as the final basis for judgment.

This means that no matter how cool your Domain Model (and supporting Service Layer) is, no one will applaud your work (except a fellow developer) unless you provide access to your model via some whiz-bang UI.

The good news is that, if you're lucky, connecting a PL to your Domain Model can be a piece of cake. The bad news is that, whenever you're not that lucky, it can be quite a challenge.

In the simplest case, your Domain Model is already "presentable" and you could just data bind directly to the Domain Model objects. However, the interface of an application frequently demands that information is presented in a more "user friendly" form than it was in the Domain Model.

Whenever the Domain Model objects fall short of being immediately presentable, you'll have to make a choice: Should you just wrap your DM objects or should you map a new set of objects to them?

For example, say that you have a DM class called Person, with FirstName and LastName properties. However, in the UI, you want to have a single text box for editing a person's full name.

One way of doing this, of course, is to have some code in your UI that simply reads from the DM Employee object's first and last names and writes to the textbox and that reads from the textbox and writes to the Employee object properties when the user hits Save.

A lot of the time, in the so called "real world," this is how UI requirements are solvedby what is essentially an accumulating heap of hacks.

In the end, this is not the path toward a maintainable application, and that is what motivates us to look for a design that will scale with increasing complexity and size of the application.

One recurring solution is to complement the Domain Model objects with a new set of objects, often referred to as the Presentation Model (PM).

The Presentation Model objects are a part of the PL and should have a structure and behavior matching the requirements of the PL (in effect, matching the needs of the UI). In our example, the PM Person class would have a FullName property rather than FirstName and LastName properties found in the Domain Model Person class.

Why not just put the GetFullName () method in the Domain Model Person class? We could, if it had a use in some business logic operation, but if the only use of the GetFullName () method is in the PL, the method should go in the PM and not in the Domain Model.

Keeping your Domain Model free of non-business aspects, such as presentation and persistence, is every bit as important as it was to keep the Business Logic Layer of yesteryear free of Presentation logic and Data Access logic, and for just the same reason: Keeping the Domain Model free from any non-business aspects is key to keeping the "heart" of your application understandable and maintainable.

So for this example, assume that GetFullName() is only used in presentation and is thus a good candidate for a method that should go on a PM rather than on the Domain Model.

The question becomes how we can connect the PM classes to the Domain Model classes, and thus we arrive at the choice: Mapping or Wrapping?

Wrapping the Domain Model with the Presentation Model

Wrapping is often the easier solution, requiring no additional framework for state management in the PM. The idea here is that you pass the DM Employee object to the constructor method of the PM Employee object. The PM Employee then keeps an internal reference to the DM object and delegates all calls to the DM properties. See the following code listing.

//Presentation Model wrapper object namespace MyCompany.MyApplication.Presentation {     public class EmployeeWrapper     {         private Employee employee;         public EmployeeWrapper (Employee employee)         {             this.employee = employee;         }         public int Id         {             get { return this.employee.Id; }             set { this.employee.Id == value; }         }         public string FullName         {             get             {                 return this.employee.FirstName + " " +                 this.employee.LastName;             }             set             {                 //This should of course be complemented with                 //some more cunning logic, as well as some                 //verification, but this is just an example...                 string[] names = value.Split(" ".ToCharArray()                     , 2);                 this.employee.FirstName = names[0];                 this.employee.LastName = names[1];             }         }     } } 


Using the EmployeeWrapper class is a matter of bringing up an Employee object from the Domain Model and then passing it to the EmployeeWrapper constructor (see the following code listing).

//Using the Presentation Model wrapper object Employee employee = employeeRepository.GetEmployeeById(42); EmployeeWrapper employeeWrapper = new EmployeeWrapper(employee); SomeControl.DataSource = employeeWrapper;


Big advantages with the wrapping approach include simplicity and flexibility. You can write pretty much any transformations you like in your wrapper objects, transformations far more complex than our relatively simple FullName transformation, if required.

A big drawback is that you will find yourself writing a lot of repetitive code in your wrapper classes for delegating to properties that don't need any transformationlike the Id property in the previous example.

This may make it tempting to just go ahead and let the Presentation Model objects inherit from the Domain Model objects instead, overriding whatever properties that need transformation, but leaving all others as they are. The problem with this is that then you are stuck with the public API of the Domain Model, because all public members of a superclass are inherited by the subclass.

In our example, we could have let the PM Employee inherit from the Domain Model Employee, and we could have added the FullName property to the PM Employee, but the PM Employee would also have exposed the FirstName and LastName properties from the Domain Model Employee, because these public properties would be inherited.

Wrapping your Domain Model objects rather than inheriting from them gives a higher level of encapsulation that is usually well worth the extra, admittedly tedious, work of delegating between PM and Domain Model properties.

Furthermore, the delegation code for properties that don't require any advanced transformations can be fruitfully attacked with code generation solutions or even just code snippet templates. If all else fails, let the intern write the boilerplate code!

Mapping the Presentation Model to Domain Model

The alternative to wrapping your DM objects with your PM objects is to actually copy the data back and forth between the DM objects and the PM objects. In this case, you'd be writing code like the following:

//Moving data manually between Presentation Model //and Domain Model Employee employee = employeeRepository.GetEmployeeById(42); EmployeeView employeeView = new EmployeeView(); employeeView.Id = employee.Id; employeeView.Salary = employee.Salary; employeeView.FullName = employee.FirstName + " " + employee.LastName;


As with the wrapping example, the code for copying the data could be placed in the constructor of the PM object, in which case the constructor would accept the DM object in a parameter. The previous example shows only the operative lines of code for clarity.

If you suffer from the same affliction as I, abstractus manicus, you will immediately recognize the potential for abstracting this work into a framework of some kind. In short, we should be able to specify (in, say, an XML file) what PM properties map to what DM properties and then let the framework use reflection to move the data.

Such a framework would have to map one set of objects to another set of objects, and so the logical term for this type of framework would be "Object/ Object Mapper"or O/O Mapper for short!

If you decide to write such a framework, you may realize that solving the non-transformational cases, such as mapping Id to Id and Salary to Salary in the previous case, should be a pretty straightforward task. Mapping FullName to First-Name and LastName, on the other hand, is trickier.

It is quite solvable, but the question becomes if it is the right approach to try to build advanced transformation services into the O/O Framework.

The alternative is to avoid charging the O/O Mapper with responsibility for actual structural transformations and let it concentrate on just moving data back and forth between objects that share the same or a very similar structure.

In our example, the solution becomes giving the PM Employee class a FirstName and a LastName property in addition to its FullName property, but also making the FirstName and LastName properties protected.

The O/O Mapper should have no problems accessing the protected PM properties using reflection, so it will be able to map to them from the Domain Model's FirstName and LastName properties, but only the FullName property will be exposed to the client by the PM object.

In fact, the O/O Mapper could even write directly to the private fields of the PM objects, so you wouldn't have to implement the protected properties at all indeed, the mapper probably should access the private fields directly in order to avoid triggering side effects in the property getters and setters that should only be invoked when client code accesses the properties, not when the framework wants to move data.

However, some O/O Mappers may offer advanced features (such as Lazy Loading) that depend on properties being there so that access to them can be intercepted, and so you may want to keep the properties around for that reason. The following code listing shows a PM object that relies on O/O Mapping.

//Presentation Model object that relies on O/O Mapping namespace MyCompany.MyProject.Presentation {     public class EmployeeView     {         private int id;         private decimal salary;         private string firstName;         private string lastName;         public EmployeeView() {}         public int Id         {             get { return this.id; }             set { this.id = value; }         }         public decimal Salary         {             get { return this.salary; }             set { this.salary = value; }         }         protected string FirstName         {             get { return this.firstName; }             set { this.firstName = value; }         }         protected string LastName         {             get { return this.lastName; }             set { this.lastName = value; }         }         public string FullName         {             get             {                 return this.firstName + " " +                 this.lastName;             }             set             {                 string[] names = value.Split(" ".ToCharArray()                     , 2);                 this.firstName = names[0];                 this.lastName = names[1];             }         }     } }


Of course, whatever you do in a framework, you could also do manually. If you were to copy the data manually from Domain Model to PM without the aid of an O/O Mapping framework, in order to write to the protected properties you could either use reflection or create shortcut methods for accessing your properties by name. Some code using the second approach might look like the following:

//Move data between Presentation and Domain Model without //transformation Employee employee = employeeRepository.GetEmployeeById(42); EmployeeView employeeView = new EmployeeView(); employeeView.Id = employee.Id; employeeView.Salary = employee.Salary; //We have to use a method that lets us access protected //properties by name to write to the protected methods. //Alternatively, we could use reflection. employeeView.SetPropertyValue("FirstName", employee.FirstName); employeeView.SetPropertyValue("LastName", employee.LastName);


Using this approach, the task of moving the data between the PM and the Domain Model becomes straightforwardalmost trivial, had it not been for the pesky reference properties.

Managing Relationships

When we take relationships between the objects into account, the task becomes more difficult again. Object graphs (a group of objects that are all interconnected via relationships) are potentially very large, and if asking the O/O Mapper to fill a PM Employee object from a DM Employee object also results in the filling up of a few hundred related objects, we may have effectively killed performance in our application.

Another issue is that you have to remember to return PM objects from PM reference properties. For example, when I read the AssignedToProject property of a PM Employee object, I want a PM Project object back, not a DM Project object. Consider a naïve implementation of a Wrapper object with a reference property as shown in the following:

//Naïve implementation of reference property in wrapper object namespace MyCompany.MyApplication.Presentation {     public class EmployeeWrapper     {         private Employee employee;         public EmployeeWrapper (Employee employee)         {             this.employee = employee;         }         public Project AssignedToProject         {             get { return this.employee.Project; }             set { this.employee.Project = value; }         }     } }


The problem here is that the Project property of the PM EmployeeWrapper object will return a DM Project object rather than a PM ProjectWrapper object. This is usually not at all what we want, and so we have to take care to write our PM reference properties in the fashion shown here:

//Slightly less naïve implementation of reference property //in wrapper object namespace MyCompany.MyApplication.Presentation {     public class EmployeeWrapper     {         private Employee employee;         public EmployeeWrapper (Employee employee)         {             this.employee = employee;         }         public ProjectWrapper AssignedToProject         {             get             {                 return new                 ProjectWrapper(this.employee.Project);             }             set             {                 this.employee.Project =                 value.GetDomainObject();             }         }         public Employee GetDomainObject()         {             return employee;         }     } }


Note the GetdomainObject() method on the ProjectWrapper class used in the AssignedToProject() setter method. When you write to the AssignedToProject property of the PM EmployeeWrapper object, you pass a ProjectWrapper object to the setter, but we have to pass a Domain Model Project object to the Project property of the wrapped Employee object. Thus we need a way to get to the required Project object from the passed in ProjectWrapper object, and the GeTDomainObject() method fills this role.

So when we implement reference properties, we suddenly have to supply a method for getting at the Domain Model object referenced internally by a PM objectsomething that might not be needed otherwise.

For completeness, and in order to be able to implement a corresponding AssignedEmployees property in the ProjectWrapper class, we have also provided a GetdomainObject() method on the EmployeeWrapper class.

But even this isn't really enough. Looking critically at the code, we can't help but notice that each time we read from the AssignedToProject property, a new ProjectWrapper object is created. Assuming the Identity Mapping in our Domain Model layer is working, each new ProjectWrapper object created when reading the same property over and over will wrap the same DM Project object, and so we shouldn't run the risk of data inconsistency and corruption, but it is hardly ideal nonetheless.

In the end, we might want a full-blown solution that could handle Identity Mapping in the PM as well, making sure that there are never two different PM instances representing the very same Domain Model instance around in a session.

The code in the AssignedToProject property would then have to be rewritten so that instead of creating a new instance of the ProjectWrapper object itself, it would ask a PM Repository with an Identity Map for the ProjectWrapper object.

That means that the EmployeeWrapper object will need a reference to the ProjectRepository object. Say goodbye to the comforting simplicity that has hitherto graced the Presentation Model. The end result is that the whole slew of fascinating and entertaining horrors and hardships that we remember from managing reference properties in the Domain Layer will rear their ugly heads again.

One way of "solving" these issues with reference properties is to simply avoid reference properties in your PM objects, using "flattened" objects instead that expose only primitive properties, quite possibly from referenced objects as well. See the following code listing.

//"Flattened" Presentation Model object, exposing only primitive //properties namespace MyCompany.MyApplication.Presentation {     public class EmployeeWrapper     {         private Employee employee;         public EmployeeWrapper(Employee employee)         {             this.employee = employee;         }         public int Id         {             get { return this.employee.Id; }             set { this.employee.Id == value; }         }         public string AssignedToProjectName         {             get { return this.employee.Project.Name; }             set { this.employee.Project.Name = value; }         }     } }


This approach is often very useful, especially because many UI controls are designed for showing tables of rows, and flattened objects adapt well to this paradigm. But whenever you are interested in representing navigable, deep structures rather than just grids of stuff, the flattened approach falls short. However, you may often find yourself complementing a fully partitioned PM with some flat objects specifically written for some grid in your application.

"Flattened" PM objects provide a good example of how the PM often looks very different from the Domain Model and, of course, the more different they are, the more motivated we are to have two separate models instead of just adding the features needed by the PL to the Domain Model.

Matters of State

When making the choice between Mapping and Wrapping, special attention should be paid to the difference in how state is handled in the two approaches.

When wrapping your Domain Model objects, only one instance of the data is used by the application. If you have two views showing the same employee at the same time, and you update the employee's name in one view, the single instance of the data in the wrapped object is updated. If the second view is then refreshed, it should display the updated data, because it is also mapping directly to the same wrapped, updated object.

When mapping your PM objects to your Domain Model objects, however, you could potentially have several different sets of PM objects representing the same Domain Model object, but with different state in them.

Even if you have an Identity Map for your PM, you may have two different PM Employee classes that look slightly different for different presentation purposes, in which case the Identity Map is of no help at all.

This could lead to conflicts. On the other hand, it also opens up the possibility of more sophisticated, disconnected data management.

For example, a mapped set of PM objects may be worked with for a long time in isolation in some wizard. At the last step of the wizard, the user could decide to commit the work to the Domain Model (and then to commit the updated Domain Model to the database) or to discard the changes. Had the user been working with a set of PM objects that directly wrapped the Domain Model objects, this option of canceling the changes would not have been available because the Domain Model objects would have been continuously updated when the user worked in the wizard!

Certainly, the option of canceling so that the changes aren't forwarded to the database is there even without the PM, assuming your Domain Model supports disconnected operations (for example, by using a Unit of Work [Fowler PoEAA]). However, if you press cancel at the end of a wizard that works directly with the Domain Model, even if your database is spared from the changes, your Domain Model will still have been changed so that when you present it in the next screen of your application, the changes are visible.

If you are prepared to throw away your Domain Model if the user cancels, there is no problem. There is also no problem if the Unit of Work supports full rollback of the state in the Domain Model. But if you are writing a rich client where you intend to let the Domain Model live for the scope of the application (for example, you don't want to throw the DM away if the user cancels) and your Unit of Work does not support full rollbacks, you may well run into this issue.

In some situations, you'll find that wrapping best suits your needs, while mapping works better in other situations. Sometimes you'll use both in the same application, perhaps using wrapping as the default approach but using mapping just for wizards or other "batch jobs" that should be possible to discard without committing.

Final Thoughts

Sometimes you're just plain lucky. Whenever you're able to present your Domain Model to the user right away (or with a minor amount of supportive hacks) you should thank your lucky stars, because there's no getting around the fact that connecting a PM to a Domain Model can be quite headache-inducing.

The headache is significantly reduced if you decide to go with "flattened" PM objects, because most of the more severe issues arise directly as a result of trying to manage reference properties.

The choice between wrapping and mapping is influenced by a number of factors, including how state is managed and the opportunities for reducing the amount of boilerplate code in your applications via code generation (wrapping) or via using an O/O Mapping framework (mapping).

By trying to keep structural transformations outside the scope of any frameworks or code generators you employ (instead placing all such advanced transformation logic in code within your PM classes and hiding non-transformed members in the PM by making them protected), you greatly reduce the complexity required by such frameworks/code generators and thereby improve your chances of writing something useful yourself or finding something available online.

If you doubt that all this extra architectural overhead in the form of PMs, O/O Mappers, and transformation logic methods is really necessaryfine, perhaps you're lucky enough to find yourself with a presentable Domain Model.

The bottom line, however, is that you should really, really try to avoid modifying the Domain Model in order to suit it to the needs of the PLdon't try to make your Domain Model work double as a PM unless you can get away with that without changing the Domain Model.

As soon as you recognize that there is a difference between the way you want to represent your Domain Model in the core of the application and the way you want to present it to the user, you recognize the need for a PMat least as long as you want to follow the advice of never burdening the Domain Model with PL aspects.

I am slightly fanatic about keeping my Domain Model objects completely oblivious of PL aspects. This means that if my Domain Model could be data bound to directly and if only some attributes were added to the properties (like attributes for specifying category and default value for binding to the property grid), I'll refrain from adding those PL attributes to my Domain Model objects. Instead I'll opt for complementing my Domain Model with a PM even if it is in every detail exactly the same as the Domain Model, except for the attributes. If you can't identify yourself with the lunatic fringe demographic, though, perhaps you'll stop short of that.

But one reason I keep doing that is that as soon as the PM is thereas well as the supporting infrastructure for Wrapping or Mapping to the Domain Model I usually find plenty of opportunity for refining the presentational aspects of the PM, and soon enough the two models will begin to become more and more different, making it easier and easier to motivate complementing the Domain Model with a PM.

Thanks, Mats!




Applying Domain-Driven Design and Patterns(c) With Examples in C# and  .NET
Applying Domain-Driven Design and Patterns: With Examples in C# and .NET
ISBN: 0321268202
EAN: 2147483647
Year: 2006
Pages: 179
Authors: Jimmy Nilsson

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net