Ravi Ganesan
Ravi Ganesan

Reputation: 295

How to Map from Dictionary to Object using Automapper?

Public class WebAction
{
   Public bool IsFbClicked {get; set;}
   Public bool IsTwitterClicked {get; set;}
}

Public enum Action
{
  IsFbClicked,
  IsTwitterClicked
}

var dictActions = new Dictionary<Action, bool>();
dictActions.add (Action.IsFbClicked, true);
dictActions.add (Action.IsTwitterClicked, false);

I tried:

cfg.CreateMap<Dictionary<Action, bool>, WebAction>()
        .ForMember(dest => dest.IsFbClicked,
                            opt => opt.MapFrom(s => s.ContainsKey(Action.IsFbClicked)))
        .ForMember(dest => dest.IsTwitterClicked,
                     opt => opt.MapFrom(s => s.ContainsKey(Action.IsTwitterClicked)))

});

It's always true for both properties in the object, which is wrong. I also tried s.TryGetValue but still no luck. Looks like containskey just checks if the keys present

Can you advise? Need help only using automapper.

Upvotes: 1

Views: 4099

Answers (2)

Ravi Ganesan
Ravi Ganesan

Reputation: 295

For future reference: To fix the problem either follow @Oliver code above or this code as @ASpirin pointed out.

    cfg.CreateMap<Dictionary<Action, bool>, WebAction>()
            .ForMember(dest => dest.IsFbClicked,
                                opt => opt.MapFrom(s => s.ContainsKey(Action.IsFbClicked)?s[Action.IsFbClicked]:fals‌​e))
            .ForMember(dest => dest.IsTwitterClicked,
                         opt => opt.MapFrom(s => s.ContainsKey(Action.IsTwitterClicked)?s[Action.IsTwitterClicked]:fals‌​e))

           });

Upvotes: 1

Oliver
Oliver

Reputation: 45119

Depending on what you'd like to achieve, there are two possibilities to solve this issue.

Create a web action for each dictionary entry

If your dictionary should be seen as a collection of items with individual states, you have to create a list of web actions for each entry in the dictionary which would look something like this:

var dictActions = new Dictionary<Action, bool>();
dictActions.Add(Action.IsFbClicked, true);
dictActions.Add(Action.IsTwitterClicked, false);

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<KeyValuePair<Action, bool>, WebAction>()
        .ForMember(webAction => webAction.IsFbClicked, conf => conf.MapFrom(kvp => kvp.Key == Action.IsFbClicked && kvp.Value))
        .ForMember(webAction => webAction.IsTwitterClicked, conf => conf.MapFrom(kvp => kvp.Key == Action.IsTwitterClicked && kvp.Value));
});

var mapper = new Mapper(config);
var items = mapper.DefaultContext.Mapper.Map<List<WebAction>>(dictActions);

foreach (var item in items)
{
    Console.WriteLine("Entry: " + "IsFb = " + item.IsFbClicked + " IsTwitter = " + item.IsTwitterClicked);
}

Create an aggregated web action for the whole dictionary

Another way would be if your dictionary is a representation of a single object that contains an entry for every property. In that case you have to map the whole dictionary to a single object:

var dictActions = new Dictionary<Action, bool>();
dictActions.Add(Action.IsFbClicked, true);
dictActions.Add(Action.IsTwitterClicked, false);

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<Dictionary<Action, bool>, WebAction>()
        .ForMember(webAction => webAction.IsFbClicked, conf => conf.MapFrom(dict => GetValue(Action.IsFbClicked, dict)))
        .ForMember(webAction => webAction.IsTwitterClicked, conf => conf.MapFrom(dict => GetValue(Action.IsTwitterClicked, dict)));
});

var mapper = new Mapper(config);
var item = mapper.DefaultContext.Mapper.Map<WebAction>(dictActions);

Console.WriteLine("Entry: " + "IsFb = " + item.IsFbClicked + " IsTwitter = " + item.IsTwitterClicked);

Helper method

private static bool GetValue(Action action, Dictionary<Action, bool> dict)
{
    var found = dict.TryGetValue(action, out bool value);
    return found && value;
}

Upvotes: 1

Related Questions