Context:
There 2 main classes that look something like this:
public class Source
{
public Dictionary<AttributeType, object> Attributes { get; set; }
}
public class Target
{
public string Title { get; set; }
public string Description { get; set; }
public List<Attribute> Attributes { get; set; }
}
And the sub / collection / Enum types:
public class Attribute
{
public string Name { get; set; }
public string Value { get; set; }
}
public enum AttributeType
{
Title,
Description,
SomethingElse,
Foobar
}
Currently my Map looks like this:
CreateMap<Source, Target>()
.ForMember(dest => dest.Description, opt => opt.MapAttribute(AttributeType.Description))
.ForMember(dest => dest.Title, opt => opt.MapAttribute(AttributeType.Title));
Where MapAttribute
gets the item from the Dictionary
and using the AttributeType
I've provided, adds it to the target collection as a (name & value) object (using a try get and returning an empty if the key does not exist)...
After all of this my Target set end's up looking like this:
{
title: "Foo",
attributes: [
{ name: "SomethingElse", value: "Bar" },
{ name: "Title", value: "Foo"}
]
}
How do I go about mapping the rest of the items to the target class, but I need to be able to exclude specific keys (like, title or description). E.G. Source.Attribute items that have a defined place in target gets excluded from the Target.Attributes collection, and "left-over" properties still go to Target.Attributes.
For even more clarity (if my source looks like this):
{ attributes: { title: "Foo", somethingelse: "Bar" } }
it would map to a target like this:
{ title: "Foo", attributes: [{ name: "SomethingElse", value: "Bar" }] }
I've attempted this, but it does not compile, stating the following:
Custom configuration for members is only supported for top-level individual members on a type.
CreateMap<KeyValuePair<AttributeType, object>, Attribute>()
.ForSourceMember(x => x.Key == AttributeType.CompanyName, y => y.Ignore())
It is possible to prefilter values on the mapping configuration, that some values would even not go to the target I'm using automapper v6.1.1, there are some difference, but the idea should be the same)
To make things works I have to add KeyValuePair<AttributeType, object>
to Attribute
mapping first (MapAttribute
just returns dictionary value)
CreateMap<KeyValuePair<AttributeType, object>, Attribute>()
.ForMember(dest => dest.Name, opt => opt.MapFrom(s => s.Key))
.ForMember(dest => dest.Value, opt => opt.MapFrom(s => s.Value));
As it's defined which attributes should be ignored, they will goes to ignore list, based on which mapping will filter out excess attributes
var ignoreAttributes = new[] {AttributeType.Description, AttributeType.Title};
CreateMap<Source, Target>()
.ForMember(dest => dest.Description, opt => opt.MapFrom(s => s.MapAttribute(AttributeType.Description)))
.ForMember(dest => dest.Title, opt => opt.MapFrom(s => s.MapAttribute(AttributeType.Title)))
.ForMember(dest=>dest.Attributes, opt=> opt.MapFrom(s=>s.Attributes
.Where(x=> !ignoreAttributes.Contains(x.Key))));
Based on the final mapping example
var result = Mapper.Map<Target>(new Source
{
Attributes = new Dictionary<AttributeType, object>
{
{AttributeType.Description, "Description"},
{AttributeType.Title, "Title"},
{AttributeType.SomethingElse, "Other"},
}
});
result will have filled Titel, Description and just one attribute SomethingElse
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