Copying Models Between Layers
When traversing layers it is very tedious to perform right->left assignments as a way to populate the models. For example:
employeeViewModel.FirstName = employeeModel.FirstName;
employeeViewModel.LastName = employeeModel.LastName;
...
So, we can build a ModelCopier which uses reflection to copy models:
var employeeViewModel = ModelCopier.Copy<EmployeeViewModel>(employeeModel);
This technique greatly simplifies the task. However, there are a few things that are quite disturbing about this:
- We have effectively lost the ability to track usages of properties on the source and destination objects. For example, finding usages (in Resharper) of the FirstName property does not reveal the ModelCopier cases.
- If we change the name of a property on the source or destination class, we can unintentionally cause runtime exceptions since we might not realize that we need to update both the source and destination class.
On one end of the spectrum, we can use reflecti开发者_开发技巧on which is very easy, but at the cost of maintainability. The opposite end of the spectrum is very tedious but very maintainable.
Reflection (Easy and Dangerous) <-----> Direct Assignment (Tedious and Maintainable)
I'm curious if anyone has found a compromise that offers the ease of using reflection for copying with the maintainability of direct assignment.
One solution we have entertained was to build a plugin that will generate extension methods that handle the assignment of properties for each case. In other words, build a tool that will handle the tedious part.
EDIT:
Please understand that this question isn't about which mapping tool to use. I'm trying to understand how we can enjoy the benefits of reflection-based mapping while also enjoying the benefits of maintainability that is provided by direct assignment (or a property map contract).
Seriously, use AutoMapper. It allows you to setup conversions from one type to another type. Any changes to property names will break the configuration of the automapper, which reflection will not:
Mapper.CreateMap<SiteDto, SiteModel>();
Mapper.CreateMap<SiteModel, SiteDto>();
Then to map to and from, you just do the following:
SiteDto dto = Mapper.Map<SiteModel, SiteDto>(targetModel);
SiteModel model = Mapper.Map<SiteDto, SiteModel>(targetDto);
Probably the compiler don't do the necessary test all over the code... that's where unit testing comes in hand. If you have defined a test for the conversion between the classes in the different layers (yes, all the possibile conversions you need to perform, otherwise how can you be sure that your reflection approach will work in every situation once in production?), simply run the test will tell the developer who changed the property name, that the solution no longer pass all the tests. You should run every test (unit test, not integration test) every time you want to check-in your source code... and that's shouldn't be a couple of months of coding :))
So I really vote for the use of the reflection approach, spicy with a spoon of unit test approach.
I'm curious if anyone has found a compromise that offers the ease of using reflection for copying with the maintainability of direct assignment.
It sounds like you are trying to have your cake and eat it.
This is a problem that dynamic languages face everyday. There is no magic pill. Either do the lefthand-righthand assignments and get the protection of the compiler or wrap your critical assignments in unit tests.
My gut tells me this is a design issue, not a code issue.
One way would be to write a separate utility that uses reflection to get the names of the properties from the model and then writes the source code to expose the properties.
your requirements go beyond runtime (implementation) as such since you (and all of us) need dependency graphs, etc. This means dynamic discovery with reflection is out. You seem to need a compile-time solution. Other than @amaca's suggestion of a code-generation plug-in (that you can write easily), what other options could there be?
精彩评论