Automapper fails for objects with collections where items use ConvertUsing<>() - automapper

My example:
class BoxVM {
int BoxId {get;set;}
List<ItemVM> Items {get;set;}
}
class Box {
int BoxId {get;set;}
List<Item> Items {get;set;}
}
With mapping config:
CreateMap<BoxVM, Box>();
CreateMap<ItemVM, Item>().ConvertUsing<ItemTypeConverter>();
When converting BoxVM will Items, the ItemTypeConverter is not called. Leaving an empty Items collection in Box.
The BoxId is being mapped correctly.
Am I missing a step?

Looks like it does work.
using System.Collections.Generic;
using AutoMapper;
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
Mapper.Initialize(cfg =>
{
cfg.CreateMap<BoxVM, Box>();
cfg.CreateMap<ItemVM, Item>().ConvertUsing<ItemTypeConverter>();
});
Mapper.AssertConfigurationIsValid();
var boxVm = new BoxVM()
{
Value1 = "5",
Items = new List<ItemVM> { new ItemVM { Name = "Item1" } }
};
var result = Mapper.Map<BoxVM, Box>(boxVm);
Assert.AreEqual(1, result.Items.Count);
}
}
public class Box
{
public string Value1 { get; set; }
public List<Item> Items { get; set; }
}
public class Item
{
public string Name { get; set; }
}
public class BoxVM
{
public string Value1 { get; set; }
public List<ItemVM> Items { get; set; }
}
public class ItemVM
{
public string Name { get; set; }
}
public class ItemTypeConverter : ITypeConverter<ItemVM, Item>
{
public Item Convert(ItemVM source, Item destination, ResolutionContext context)
{
return new Item { Name = source.Name };
}
}

Related

Automapper - How to map object to list

ValueList model is
public class ValueList
{
[Key]
public int Id { get; set; }
public List<string> Values { get; set; }
}
Value Model is >
public Value();
[JsonProperty(PropertyName = "id")]
[Key]
public int Id { get; set; }
[JsonProperty(PropertyName = "value")]
public decimal Value { get; set; } }
CreateMap<Value, ValuesList>()
.ForMember( ???? )
I want >
ValueList [{ id, Value }, { id, Value }, { id, Value }]
CreateMap<Value,ValuesList>.ConvertUsing<ValueConverter>()
then create:
public class ValueConverter: ITypeConverter<Value,ValuesList>
{
public ValuesList Convert(Value source, ValuesList destination, ResolutionContext context)
{
// Create destination object here
return destination;
}
}

Automapper Object with inside list of object to primitive mapping

I'm trying to create map for automapper to let me map those entity
Entities
public class Entity
{
...
public List<NavigationEntity> Navs { get; set; }
}
public class NavigationEntity
{
public int Id { get; set; }
}
DTO that need to be create with entities
public class EntityDto
{
...
public List<int> NavIds { get; set; }
}
This doesnt seem's to do the job! What could do the job ?
CreateMap<Entity, EntityDto>().ReverseMap();
CreateMap<NavigationEntity, int>().ConstructUsing(x => x.Id);
EDIT
Tried to add
CreateMap< List < SystemsTags >, List< int >>();
but still it doesnt map
First of all, you should rename public List<NavigationEntity> Navs { get; set; } and public List<int> NavIds { get; set; } to the same name. If it is still not working try to also change ConstructUsing to ConvertUsing. And if you need the reverseMap of Entity to EntityDTO you should also add
CreateMap<int, NavigationEntity>().ConvertUsing(x => new NavigationEntity { Id = x });
final code
public class Entity
{
...
public List<NavigationEntity> Navs { get; set; }
}
public class NavigationEntity
{
public int Id { get; set; }
}
public class EntityDto
{
...
public List<int> Navs { get; set; }
}
...
CreateMap<Entity, EntityDto>().ReverseMap();
CreateMap<NavigationEntity, int>().ConvertUsing(x => x.Id);
CreateMap<int, NavigationEntity>().ConvertUsing(x => new NavigationEntity { Id = x });

Azure Table Storage Entity Row/Primary Key as Attribute for existing properties

I already have entity migrated from EntityFramework.
I'm don't want override some propeties and Convert it to string
public class User : TableEntity, ITableStorageEntity<int, Guid>
{
[RowKey]
public Guid ID { get; set; }
[PartitionKey]
public int LanguageID { get; set; }
It's possible ? I don't want override ReadEntity/WriteEntity.
Since your class is already based on TableEntity, you might want to try to override/replace the row key and partition key property of TableEntity using the 'new' keyword instead.
public class User : TableEntity
{
[IgnoreProperty]
public Guid ID { get; set; }
[IgnoreProperty]
public int LanguageID { get; set; }
public new string PartitionKey { get { return ID.ToString(); } set { ID = Guid.Parse(value); } }
public new string RowKey { get { return LanguageID.ToString(); } set { LanguageID = int.Parse(value); } }
}
I am not a big fan of 'new' modifier. In my opinion it is non-OOP approach.
I will suggest following
public class ConsumerApplicationEntity : TableEntity
{
public ConsumerApplicationEntity(string applicationKey, string applicationSecret)
: base(applicationKey, applicationSecret)
{
}
[IgnoreProperty]
public string ApplicationKey
{
get
{
return this.PartitionKey;
}
set
{
this.PartitionKey = value;
}
}
[IgnoreProperty]
public string ApplicationSecret
{
get
{
return this.RowKey;
}
set
{
this.RowKey = value;
}
}
}

Mapping into differnet types with Automapper

There are two classes in my Model:
public class Operation
{
public string Name { get; set; }
public Calculation Details { get; set; }
}
public class Calculation
{
public long Value { get; set; }
public List<decimal> Points { get; set; }
}
Mapping into this DTO:
public class OperationDto
{
public string Name { get; set; }
public CalculationDto Details { get; set; }
}
public class CalculationDto
{
public long Value { get; set; }
}
public class CalculationDetailedDto: CalculationDto
{
public List<decimal> Points { get; set; }
}
And sometimes the Client can request detailed information about the calculation. For example, depending of the command-line options:
class Program
{
static void Main(string[] args)
{
Mapper.CreateMap<Operation, OperationDto>();
Mapper.CreateMap<Calculation, CalculationDto>();
Mapper.CreateMap<Calculation, CalculationDetailedDto>();
var operation = new Operation
{
Name = "Very complicated opertion.",
Details =
new Calculation
{
Value = 1002,
Points = new List<decimal> {1.2m, 2.4m, 3.7m}
}
};
var operationDto = Mapper.Map<OperationDto>(operation);
Debug.WriteLine("Operation name: '{0}' value: '{1}'", operationDto.Name, operationDto.Details.Value);
if (args.Length > 0)
{
Debug.WriteLine("Details:");
foreach (var point in ((CalculationDetailedDto) operationDto.Details).Points)
{
Debug.WriteLine("{0}", point);
}
}
}
How do i tell Automapper at runtime map the calculation into CalculationDetailedDto?
You need to create another OperationDto that uses the detailed calculationDto, and create a map from Operation to OperationDetailedDto:
public class OperationDetailedDto
{
public string Name { get; set; }
public CalculationDetailedDto Details { get; set; }
}
Mapper.CreateMap<Operation, OperationDetailedDto>();
if (detailed) operationDto = Mapper.Map<Operation, OperationDto>(operation);
else operationDto = Mapper.Map<Operation, OperationDetailedDto(operation);
For those who do not fit solution proposed #fiskeboss can use the following.
You can re-map Calculation to CalculationDetailedDto after checking the command line arguments.
if (args.Length > 0)
{
operationDto.Details = Mapper.Map<CalculationDetailedDto>(operation.Details);
Debug.WriteLine("Details:");
foreach (var point in ((CalculationDetailedDto) operationDto.Details).Points)
{
Debug.WriteLine("{0}", point);
}
}

Complex collections with Automapper

Here is what I have where I hope someone can help us out:
class Source
{
string name { get; set; }
Inner { get; set; }
}
class Inner
{
Col A { get; set; }
Col B { get; set; }
}
class Col : IList<ClassX>, IEnunmerable<ClassX>
I need to map class Source to a destination type which has:
class Dest
{
string name { get; set; }
IList<ClassY> A { get; set;}
IList<ClassY> B { get; set;}
}
Now, ClassX and class ClassY share the same properties. ClassY class has a subset of the ClassX primitive properties with the exact same names and types.
Tried all kinds of mappings. Just the ClassX to ClassY map, with the collections, without and with any mapping get no mapping found between or missing configuration between Source and Dest
AutoMapper.Mapper.Map<Source, Dest>(src);
Can someone help me out with the mapping? Thanks in advance.
This question is a few months old, but if you're still looking for an answer, this is what I tried that worked:
class Source
{
public string Name { get; set; }
public Inner Inner { get; set; }
}
class Inner
{
public Col A { get; set; }
public Col B { get; set; }
}
class Col : List<ClassX> { }
class ClassX
{
public int Index { get; set; }
public string Name { get; set; }
public ClassX() : this(0, "") { }
public ClassX(int index, string name)
{
this.Index = index;
this.Name = name;
}
}
class ClassY
{
public int Index { get; set; }
public string Name { get; set; }
public ClassY() : this(0, "") { }
public ClassY(int index, string name)
{
this.Index = index;
this.Name = name;
}
}
class Dest
{
public string Name { get; set; }
public List<ClassY> A { get; set; }
public List<ClassY> B { get; set; }
}
[TestMethod]
public void ComplexTest()
{
Mapper.CreateMap<Source, Dest>()
.ForMember(dest => dest.A, config => config.MapFrom(src => src.Inner.A))
.ForMember(dest => dest.B, config => config.MapFrom(src => src.Inner.B));
Mapper.CreateMap<ClassX, ClassY>();
Source source = new Source
{
Name = "Source",
Inner = new Inner
{
A = new Col
{
new ClassX(1, "First"),
new ClassX(2, "Second"),
new ClassX(3, "Third"),
new ClassX(4, "Fourth"),
},
B = new Col
{
new ClassX(5, "Fifth"),
new ClassX(6, "Sixth"),
new ClassX(7, "Seventh"),
new ClassX(8, "Eighth"),
},
}
};
Dest destination = Mapper.Map<Source, Dest>(source);
Assert.AreEqual(source.Name, destination.Name);
Assert.AreEqual(source.Inner.A.Count, destination.A.Count);
Assert.AreEqual(source.Inner.B.Count, destination.B.Count);
Assert.AreEqual(source.Inner.A[0].Name, destination.A[0].Name);
Assert.AreEqual(source.Inner.B[0].Name, destination.B[0].Name);
}
I didn't go too in-depth with my Asserts, so there may be something I missed, but they appear to be mapped properly.

Resources