AutoMapper with prefix - c#

I'm trying to use Automapper to map to objects, the issue is one of the objects I'm trying to map has a prefix 'Cust_' in front of all its properties and one doesn't. Is there a way to make this mapping.
For example say I have
class A
{
String FirstName { get; set; }
String LastName { get; set; }
}
class B
{
String Cust_FirstName { get; set; }
String Cust_LastName { get; set; }
}
Obviously this map won't work
AutoMapper.Mapper.CreateMap<A, B>();
b = AutoMapper.Mapper.Map<A, B>(a);

Mapper.Initialize(cfg =>
{
cfg.RecognizeDestinationPrefixes("Cust_");
cfg.CreateMap<A, B>();
});
A a = new A() {FirstName = "Cliff", LastName = "Mayson"};
B b = Mapper.Map<A, B>(a);
//b.Cust_FirstName is "Cliff"
//b.Cust_LastName is "Mayson"
Or alternatively:
Mapper.Configuration.RecognizeDestinationPrefixes("Cust_");
Mapper.CreateMap<A, B>();
...
B b = Mapper.Map<A, B>(a);
...

The documentation has an article on Recognizing pre/postfixes
Sometimes your source/destination properties will have common pre/postfixes that cause you to have to do a bunch of custom member mappings because the names don't match up. To address this, you can recognize pre/postfixes:
public class Source {
public int frmValue { get; set; }
public int frmValue2 { get; set; }
}
public class Dest {
public int Value { get; set; }
public int Value2 { get; set; }
}
Mapper.Initialize(cfg => {
cfg.RecognizePrefix("frm");
cfg.CreateMap<Source, Dest>();
});
Mapper.AssertConfigurationIsValid();
By default AutoMapper recognizes the prefix "Get", if you need to clear the prefix:
Mapper.Initialize(cfg => {
cfg.ClearPrefixes();
cfg.RecognizePrefixes("tmp");
});

Related

Mapster and nonmatching member names

When field names don't match, Mapster won't map. Fields are set to nulls or zeroes depending on type.
How do I use custom names for target attributes?
Ex.: How do I change SchoolClassTeacherName to just Name? Changing it in the code below and in class SchoolDTO gives me null as a result of mapping.
I've read the documentation but there is no answer. Please, help me. Thank you.
config.NewConfig<SchoolPoco, SchoolDTO>()
.Map(dest => dest.SchoolClassTeacherName,
src => src.School.Class.Teacher.Name)
I have this in my Startup.cs
var typeAdapterConfig = TypeAdapterConfig.GlobalSettings;
typeAdapterConfig.Scan(Assembly.GetExecutingAssembly());
var mapperConfig = new Mapper(typeAdapterConfig);
services.AddSingleton<IMapper>(mapperConfig);
I have mapping in a class
public class ProjectMappingProfile : IRegister
{
void IRegister.Register(TypeAdapterConfig config)
{
// Mappings here
}
}
Use TypeAdapterConfig as described in documentation.
Make sure that School, Class, Teacher, Name properties is set.
Sample code:
using Mapster;
TypeAdapterConfig<DtoA, DtoB>
.NewConfig()
.Map(dest => dest.Main_Property, src => src.MainProperty)
.Map(dest => dest.Inner_Property, src => src.InnerDto.InnerProperty);
DtoA a = new DtoA()
{
MainProperty = "Hello",
InnerDto = new InnerDto() { InnerProperty = "World" }
};
DtoB b = a.Adapt<DtoB>();
class DtoA
{
public string MainProperty { get; set; }
public InnerDto InnerDto { get; set; }
}
class InnerDto
{
public string InnerProperty { get; set; }
}
class DtoB
{
public string Main_Property { get; set; }
public string Inner_Property { get; set; }
}
Result in b variable:

How to convert a nested object to object in C#

Is there a way to convert a nested object to an object. For example lets say I have an object of class ABC as shown below.
class ABC
{
int id {get;set;}
XYZ myobj {get;set}
}
class XYZ
{
string name {get;set;}
string addr {get;set;}
}
Is there any way to convert this ABC class object to UVW class object like below.
class UVW
{
int id {get;set;}
string name {get;set;}
string addr {get;set;}
}
If you are looking for a provision in C# to convert an object of ABC to an object of UVW, then am afraid there is no such thing.
If you want, you could just write your own conversion logic though (after making the properties public):
private UVW ConvertToUVW(ABC abc)
{
if (abc == null)
{
return null;
}
var uvw = new UVW();
uvw.id = abc.id;
uvw.name = abc.myobj?.name;
uvw.addr= abc.myobj?.addr;
return uvw;
}
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".

AutoMapper does not update nested collection

I am trying to simplify a process of mapping classes. For this purpose I am using AutoMapper. If no one of classes does not have a nested collection then all is great. But if someone have, I have a trouble with mapping. Collection into a class is overwriting. I found an extension AutoMapper.Collection. But it does not work for me.
I am working on a web api project, so some parts of codes here:
// Classes for mapping
public class A_Dto
{
public int Id { get; set; }
public List<A_SubItem_Dto> SubItems { get; set; }
}
public class A_SubItem_Dto
{
public int Id { get; set; }
public string Value { get; set; }
public A_Dto A_MainObject { get; set; }
}
public class A_Resource
{
public int Id { get; set; }
public List<A_SubItem_Resource> SubItems { get; set; }
}
public class A_SubItem_Resource
{
public int Id { get; set; }
public string Value { get; set; }
}
// Configure AutoMapper
public void ConfigureServices(IServiceCollection services)
{
services.AddAutoMapper(cfg => cfg.AddCollectionMappers(), typeof(Startup));
}
// Configure profile class for mapping
public class AutoMapping : Profile
{
CreateMap<A_Dto, A_Resource>().ReverseMap()
.ForMember(m => m.Id, opt => opt.Ignore());
CreateMap<A_SubItem_Dto, A_SubItem_Resource>().ReverseMap()
.EqualityComparison((sir, si) => sir.Id == si.Id);
}
// Controller action with simple test
public async Task<IActionResult> Put(/*...*/)
{
// Test
var aDto = new A_Dto()
{
Id = 7,
SubItems = new List<A_SubItem_Dto>()
{
new A_SubItem_Dto() { Id = 2, Value = "_2_" },
new A_SubItem_Dto() { Id = 9, Value = "_9_" }
}
};
var aResource = new A_Resource()
{
Id = 7,
SubItems = new List<A_SubItem_Resource>()
{
new A_SubItem_Resource() { Id = 2, Value = "_222222_" }
}
};
_mapper.Map(aResource, aDto);
}
In result aDto object contains new collection with one element of aResource.SubItems
Could you tell me please, what I am doing wrong?

automapper working with attributes c#

I have two objects, I want to map them using AutoMapper Attributes, these are my target objects:
public class ClaseB
{
public string UBLVersionID_nuevo { get; set; }
public ClaseB_inside objetoB_inside { get; set; }
}
public class ClaseB_inside
{
public string texto_inside { get; set; }
}
and this is my source class:
[MapsTo(typeof(ClaseB))]
public class ClaseA
{
[MapsToProperty(typeof(ClaseB), "objetoB_inside.texto_inside")]
public string texto { get; set; } = "texto prueba";
[MapsToProperty(typeof(ClaseB), "UBLVersionID_nuevo")]
public string texto2 { get; set; } = "texto 2 de prueba";
}
when I try to map I get the following error:
Error mapping types
and with this change:
[MapsTo(typeof(ClaseB))]
public class ClaseA
{
[MapsToProperty(typeof(ClaseB_inside), "objetoB_inside.texto_inside")]
public string texto { get; set; } = "texto prueba";
[MapsToProperty(typeof(ClaseB), "UBLVersionID_nuevo")]
public string texto2 { get; set; } = "texto 2 de prueba";
}
I get null in ClaseB.objetoB_inside but ClaseB.UBLVersionID_nuevo it works.
What am I doing wrong?
I think the issue is with the way you are defining the mapping. Consider the following if you weren't using Automapper attributes and was initializing through the static API:
Mapper.Initialize(expression =>
{
expression.CreateMap<ClaseA, ClaseB>()
.ForMember(
from => from.objetoB_inside.texto_inside,
to => to.MapFrom(a => a.texto2));
});
This mapping would result in the following exception:
Expression 'from => from.objetoB_inside.texto_inside' must resolve to top-level member and not any child object's properties. Use a custom resolver on the child type or the AfterMap option instead.
And I think that's the same issue with the Attributes definition.
So I would suggest implementing the following:
public class MapsToClaseB : MapsToAttribute
{
public MapsToClaseB() : base(typeof(ClaseB)) { }
public void ConfigureMapping(IMappingExpression<ClaseA, ClaseB> mappingExpression)
{
mappingExpression.AfterMap(
(a, b) => b.objetoB_inside = new ClaseB_inside{texto_inside = a.texto});
}
}
You just then need to decorate your class with this:
[MapsToClaseB]

Automapper - Map custom object nested inside List of object

I need to map List<Source> to List<Dest>, The issue is that Source contains NestedObject inside it & Dest also contains a NestedObject inside it. I need to map these two also while my List is being mapped. I have tried everything but either the nested object always remains null and doesnt get mapped or I get the following exception:
Missing type map configuration or unsupported mapping. Mapping types:
.....
Structure of Source & Destinations:
Source:
public class Source {
public string Prop1 { get; set; }
public CustomObjectSource NestedProp{ get; set; }
}
public class CustomObjectSource {
public string Key { get; set; }
public string Value{ get; set; }
}
Destination:
public class Destination {
public string Prop1 { get; set; }
public CustomObjectDest NestedProp{ get; set; }
}
public class CustomObjectDest {
public string Key { get; set; }
public string Value{ get; set; }
}
What I have tried:
I have the following code, tried several other approaches also but to no avail:
var config = new MapperConfiguration(c =>
{
c.CreateMap<Source, Destination>()
.AfterMap((Src, Dest) => Dest.NestedProp = new Dest.NestedProp
{
Key = Src.NestedProp.Key,
Value = Src.NestedProp.Value
});
});
var mapper = config.CreateMapper();
var destinations = mapper.Map<List<Source>, List<Destination>>(MySourceList.ToList());
I am stuck with this for days, Kindly help.
You got to map the CustomObjectSource to CustomObjectDest as well.
This should do it:
var config = new MapperConfiguration(c =>
{
c.CreateMap<CustomObjectSource, CustomObjectDest>();
c.CreateMap<Source, Destination>()
.AfterMap((Src, Dest) => Dest.NestedProp = new CustomObjectDest
{
Key = Src.NestedProp.Key,
Value = Src.NestedProp.Value
});
});
var mapper = config.CreateMapper();
var MySourceList = new List<Source>
{
new Source
{
Prop1 = "prop1",
NestedProp = new CustomObjectSource()
{
Key = "key",
Value = "val"
}
}
};
var destinations = mapper.Map<List<Source>, List<Destination>>(MySourceList.ToList());

Categories

Resources