-
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
Map
s looking for a correspondingPatchOperation
. If one is not found, the map is skipped. This means the order of your definedMap
s is important: in the example above you can expect the propertyName
to have already been updated (if applicable) when theUrl
map is run - If a matching
PatchOperation
was found:- If this is a
JsonPatch
and the value is not parsable (i.e. the field is anInt
but 'ABC' was passed in), we stop processing the map here with a result ofJsonPatchValueNotParsable
. - If the map has a
Enabled
hook defined, run that now to determine if we should proceed. If the result istrue
, continue - If the map has a
Converter
hook 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
ValueConversionFailed
and 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
Required
hook, run that now. - The mapper itself has a
MapTargetIsRequired
method 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
Required
hook returnedtrue
, or there was no hook andMapTargetIsRequired
returnedtrue
, 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
MapTargetValueIsValid
method, 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
MapTargetValueIsValid
returnedfalse
, we stop processing the map here with a result ofValueIsNotValid
and 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
MapTargetHasChanged
method, 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 allPostMap
methods 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
PostMap
hook 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 theCompoundMap
sPostMap
method 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