-
Notifications
You must be signed in to change notification settings - Fork 0
Mapper
jayoungers edited this page Oct 12, 2018
·
3 revisions
The PatchMap.Mapper is the heart of the library: for a given entity, the Mapper should be defined once (usually statically), and Map will be called given the current PatchContext:
public class BlogPatchCommand
{
private static readonly Mapper<BlogViewModel, Blog, BasePatchContext> mapper = new Mapper<BlogViewModel, Blog, BasePatchContext>();
static BlogPatchCommand()
{
mapper.AddMap(vm => vm.Name, db => db.Name);
mapper.AddMap(vm => vm.Url, db => db.Url);
}
public PatchCommandResult<BlogViewModel> Execute(int? blogId, List<PatchOperation> operations)
{
//Get or create the entity dbBlog
var results = mapper.Map(operations, dbBlog, GenerateContext(isNew));
//Return results
}
}Given a set of PatchOperations, Map will work the following way:
- Iterate through the collection of defined
Maps looking for a correspondingPatchOperation. If one is not found, the map is skipped. This means the order of your definedMaps is important: in the example above you can expect the propertyNameto have already been updated (if applicable) when theUrlmap is run - If a matching
PatchOperationwas found:- If this is a
JsonPatchand the value is not parsable (i.e. the field is anIntbut 'ABC' was passed in), we stop processing the map here with a result ofJsonPatchValueNotParsable. - If the map has a
Enabledhook defined, run that now to determine if we should proceed. If the result istrue, continue - If the map has a
Converterhook defined and the value is not null, run that now- If the conversion did not succeed, we stop processing the map here with a result of
ValueConversionFailedand the reason for the failure.
- If the conversion did not succeed, we stop processing the map here with a result of
- At this point, if the value is null (or in the case of string:
IsNullOrEmpty), we determine if the map is Required.- If the map has a
Requiredhook, run that now. - The mapper itself has a
MapTargetIsRequiredmethod which can be overwritten. By default, this will always return false. It's recommended to overwrite this with the logic of:Field is not nullable - If the
Requiredhook returnedtrue, or there was no hook andMapTargetIsRequiredreturnedtrue, we stop processing the map here with a result ofRequired.
- If the map has a
- If this map has a target field:
- Determine if its a valid value based on the mapper's
MapTargetValueIsValidmethod, which can be overwritten. By default this will always return true. It's recommended to overwrite this with logic based on your entity store meta-data (i.e. check for string max lengths, valid date ranges, etc). - If
MapTargetValueIsValidreturnedfalse, we stop processing the map here with a result ofValueIsNotValidand the reason for the failure. - If it returned
true:- We update the target field with the new value.
- Determine if the value has changed based on the mapper's
MapTargetHasChangedmethod, which can be overwritten. By default it will return a simple!Equals(oldValue, newValue)comparison: it's recommended to update this toEntity is new or !Equals(oldValue, newValue), so that allPostMapmethods are executed when dealing with new entities, even if the value was not set.
- Determine if its a valid value based on the mapper's
- If the target field's value has changed, or if this map does not target a field (i.e. is a collection), run the map's
PostMaphook if it has been defined.
- If this is a
- While iterating through the collection of maps, if we run across a
CompoundMap, we run the above process for each of its maps. If any of those maps resulted in a change, we run theCompoundMapsPostMapmethod if defined.
The reason the Mapper's MapTargetHasChanged, MapTargetIsRequired, MapTargetValueIsValid hooks are over-writable is to prevent the library from being tied to any one specific implementation of object-relational mapping: each has their own way of handling table metadata (column definitions, etc). The examples section of this repository and wiki include the recommended ways to overwrite these method for both EF6 and EFCore.
Concepts
PatchMap Library
Examples