Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to ignore a property based on a runtime condition?

Tags:

c#

automapper

I have a simple pair of classes which for I've set up a mapping at initialization time.

public class Order {
  public int ID { get; set; }  
  public string Foo { get; set; }
}

public class OrderDTO {
  public int ID { get; set; }
  public string Foo { get; set; }
}

...

Mapper.CreateMap<Order, OrderDTO>();

Now at a certain point I need to map an Order to an OrderDTO. BUT depending on some circumstances, I might need to ignore Foo during mapping. Let's also assume that I cannot "store" the condition in the source or destination object.

I know how I can configure the ignored properties at initialization time, but I have no idea how I could achieve such a dynamic runtime behavior.

Any help would be appreciated.

UPDATE

My use case for this behaviour is something like this. I have an ASP.NET MVC web grid view which displays a list of OrderDTOs. The users can edit the cell values individually. The grid view sends the edited data back to the server like a collection of OrderDTOs, BUT only the edited field values are set, the others are left as default. It also sends data about which fields are edited for each primary key. Now from this special scenario I need to map these "half-empty" objects to Orders, but of course, skip those properties which were not edited for each object.

The other way would be to do the manual mapping, or use Reflection somehow, but I was just thinking about if I could use AutoMapper in some way.

like image 701
Zoltán Tamási Avatar asked Dec 18 '22 20:12

Zoltán Tamási


1 Answers

I've digged into the AutoMapper source code and samples, and found that there is a way to pass runtime parameters at mapping time.

A quick example setup and usage looks like this.

public class Order {
  public int ID { get; set; }  
  public string Foo { get; set; }
}

public class OrderDTO {
  public int ID { get; set; }
  public string Foo { get; set; }
}

...

Mapper.CreateMap<Order, OrderDTO>()
  .ForMember(e => e.Foo, o => o.Condition((ResolutionContext c) => !c.Options.Items.ContainsKey("IWantToSkipFoo")));

...

var target = new Order();
target.ID = 2;
target.Foo = "This should not change";

var source = new OrderDTO();
source.ID = 10;
source.Foo = "This won't be mapped";

Mapper.Map(source, target, opts => { opts.Items["IWantToSkipFoo"] = true; });
Assert.AreEqual(target.ID, 10);
Assert.AreEqual(target.Foo, "This should not change");

In fact this looks quite "technical", but I still think there are quite many use cases when this is really helpful. If this logic is generalized according to application needs, and wrapped into some extension methods for example, then it could be much cleaner.

like image 123
Zoltán Tamási Avatar answered Dec 29 '22 00:12

Zoltán Tamási