I am trying to implement propertywise version tracking in my entities. Using the schema of TrackedProperty
for my trackable properties;
public class PropertyVersion<TValue, TVersion>
{
public TVersion Version { get; set; }
public TValue Value { get; set; }
}
public class TrackedProperty<TValue, TVersion> : List<PropertyVersion<TValue, TVersion>>
{
}
For example, In my repository, I will keep the TrackedFoo
object and I will be able to retrieve the data at a specific version (in this case the version is described as a Time object) in Foo
from.
public class TrackedFoo
{
public string Id { get; set; }
public TrackedProperty<string, DateTime> Name { get; set; }
}
public class Foo
{
public string Id { get; set; }
public string Name { get; set; }
}
I would like to keep things generic as much as possible. So I tried to use AutoMapper but I wasn't able to configure it in a generic way which I won't need to configure mapping of every single TrackedTypeX
to TypeX
.
I need to get the last PropertyVersion item in TrackedProperty and map its Value property to a TValue type
Can you please help me find a solution for this problem?
I can reduce the number of variable types (is that what you call the stuff between <> ?, anyway) to single using
DateTrackedProperty<TValue> : TrackedProperty<TValue,DateTime>
IntegerTrackedProperty<TValue> : TrackedProperty<TValue, int>
StringTrackedProperty<TValue> : TrackedProperty<TValue, string>
I am ok with having to write AutoMapper configuration for these three types.
If you have to do complex mapping behavior, it might be better to avoid using AutoMapper for that scenario. Reverse mapping can get very complicated very quickly, and unless it's very simple, you can have business logic showing up in mapping configuration.
Yes, or you can call CreateMap<ModelClass, ViewModelClass>(). ReverseMap() .
At the end I managed to create a generic mapping profile (only one way) by placing the following in my MappingProfile
CreateMap(typeof(PropertyVersion<,>), typeof(object)).ConvertUsing(typeof(PropertyVersionToValueConverter<,>));
CreateMap(typeof(TrackedProperty<,>), typeof(PropertyVersion<,>)).ConvertUsing(typeof(TrackedPropertyToPropertyVersionConverter<,>));
CreateMap(typeof(TrackedProperty<,>), typeof(object)).ConvertUsing(typeof(TrackedPropertyToValueConverter<,>));
where
public class PropertyVersionToValueConverter<TValue, TVersion> : ITypeConverter<PropertyVersion<TValue, TVersion>, TValue>
{
public TValue Convert(PropertyVersion<TValue, TVersion> source, TValue destination, ResolutionContext context)
{
if (source != null)
return source.Value;
return default(TValue);
}
}
public class TrackedPropertyToPropertyVersionConverter<TValue, TVersion> : ITypeConverter<TrackedProperty<TValue, TVersion>, PropertyVersion<TValue, TVersion>>
{
public PropertyVersion<TValue, TVersion> Convert(TrackedProperty<TValue, TVersion> source, PropertyVersion<TValue, TVersion> destination, ResolutionContext context)
{
if (source != null && source.Count > 0)
return source.Last();
else return default(PropertyVersion<TValue, TVersion>);
}
}
public class TrackedPropertyToValueConverter<TValue, TVersion> : ITypeConverter<TrackedProperty<TValue, TVersion>, TValue>
{
public TValue Convert(TrackedProperty<TValue, TVersion> source, TValue destination, ResolutionContext context)
{
var vers = context.Mapper.Map(source, typeof(TrackedProperty<TValue, TVersion>), typeof(PropertyVersion<TValue,TVersion>));
return (TValue)context.Mapper.Map(vers, typeof(PropertyVersion<TValue, TVersion>), typeof(TValue));
}
}
The first mapping line extracts PropertyVersion.Value.
The second mapping line assumes I need only the last version in TrackedProperty and extracts that one.
The third line brings everything together.
I could probably combine everything into one and have one CreateMap line and one Converter but that's trivial.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With