You can use Automapper's automatic flattening for this. It works by naming convention, to map a Foo.Bar in the source to a FooBar destination, or by configuration where the first configured match wins in case of conflicts.
Given these source types:
class SourceRoot
{
public int Id { get; set; }
public Foo Foo { get; set; }
public Bar Bar { get; set; }
}
class Foo
{
public string Name { get; set; }
public string Addr { get; set; }
}
class Bar
{
public string Name { get; set; }
public string Addr { get; set; }
}
Which is to be mapped to this target:
class TargetFlattened
{
public int Id { get; set; }
public string Name { get; set; }
public string Addr { get; set; }
public string BarAddr { get; set; }
}
You can automap from source to flattened target like this:
var source = new SourceRoot
{
Id = 42,
Foo = new Foo
{
Addr = "FooAddr",
Name = "FooName"
},
Bar = new Bar
{
Addr = "BarAddr",
Name = "BarName"
}
};
var configuration = new MapperConfiguration(cfg => {
// First, map complex property types
cfg.CreateMap<Foo, TargetFlattened>();
cfg.CreateMap<Bar, TargetFlattened>();
// Then the root type
cfg.CreateMap<SourceRoot, TargetFlattened>()
.IncludeMembers(a => a.Foo, a => a.Bar)
.ReverseMap();
});
var target = configuration.CreateMapper().Map<TargetFlattened>(source);
Note that this will yield:
Id: 42
Addr: FooAddr
BarAddr: BarAddr
Name: FooName
The IncludeMembers() configuration will map members that don't adhere to the naming convention (Name instead of FooName for Foo.Name).
Meaning, if you have multiple complex properties with a Name property, you'll get the first included member's Name property mapped into your target's Name.
If you swap them to .IncludeMembers(a => a.Bar, a => a.Foo), your Name will be "BarName".
UVW.id = abc.id?