Conditional mapping

Jan 27, 2010 at 6:59 PM

Hi,

I have two classes with different properties names. User can choose which fields and how should be mapped. See example below.

class A
{
  public int Id {get;set;}
  public string Subject {get;set;}
  public string Note {get;set;}
}

class B
{
  public string Prop1 {get;set;}
  public string Prop2 {get;set;}
  public string Prop3 {get;set;}
}

User fill dictionary<string, string>. Pairs for example:

pairs.Add("Id", "Prop2");
pairs.Add("Subject", "Prop3");
pairs.Add("Note", "Prop1");

Also user can specify which properties should be skipped during  mapping

mapping.Add("Id", true);
mapping.Add("Subject", false);
mapping.Add("Note", true);

Can you help me how to create mapping config? I did following

class AtoBMapConfig : DefaultMapConfig
{
  protected override bool MatchMembers(string sourceProperty, string destProperty)
  {
    string value;
    if(_fieldsMapping.TryGetValue(sourceProperty, out value))
      return value == destProperty;
    else
      return false;
  }
}

This config helps to solve problem with properties names. But how to take into account which properties should be skipped. I think i have to override GetMappingOperations and generate operations with delegate. But i cannot understand which operation class i should use. Who can help with example.

Thanks a lot.

Coordinator
Jan 27, 2010 at 7:57 PM
Edited Jan 27, 2010 at 7:59 PM

Hi,

You can add an additional checking to the MatchMembers function:

var mapConfig = new DefaultMapConfig().MatchMembers((m1, m2) => pai$rs[m1] == m2 && mapping[m1]);

...

var mapper = ObjectMapperManager.DefaultInstance.GetMapper<Source, Destination>(mapConfig);

 

Also you can use "IgnoreMembers" configuration function: http://emitmapper.codeplex.com/wikipage?title=Customization%20using%20default%20configurator&referringTitle=Home&ANCHOR#Ignoring_members

Jan 28, 2010 at 9:04 AM

Thanks, and one more question about performance.
A User setups properties names mapping only one time (by app.config). But user very often change which properties should be skipped during mapping.
In your example i should create mapConfig instance every time. In this case we will generate new code every time. Am i right? I didn't test speed. But should i think about this and try to implement complex operation? Or can i forget about this and use your solution as true way?

Coordinator
Jan 30, 2010 at 8:08 AM

EmitMapper will not generate mappers every time - it caches them. To force the library generate new mapper when mapping should be updated use the configuration method "SetConfigName" wich has one parameter - unique mapping configuration identifier. So, when you know that mapper should be updated pass there a new string value (for example it can be a guid). Also you can store generated mapper in some variable which is accessible from different modules (for example it can be a singleton) and when user updates configuration then new mapper is generated and stored to this variable.

Jan 30, 2010 at 8:08 PM

I don't want to add caching responsibility to my code. Good hint about SetConfigName. I will use it.