I want to map my DTO to an entity. The only difference between the two is my dto's use List as collection type and the entities use HashSet. How can I configure Automapper to automatically map to a HashSet when it encounters an ICollection? Currently it just replaces the hashset in the entity with a List.
Example classes and mapping:
cfg.CreateMap<MachineDto, Machine>(MemberList.Source)
cfg.CreateMap<Machine, MachineDto>(MemberList.Destination)
public class Machine
{
public Machine()
{
Segment = new HashSet<Segment>();
}
public long ID { get; set; }
public string Name { get; set; }
public ICollection<Segment> Segment { get; set; }
}
public class Segment
{
public Segment()
{
}
public long ID { get; set; }
public long MachineID { get; set; }
public string Serial { get; set; }
}
public class MachineDto
{
public MachineDto()
{
Segment = new List<SegmentDto>();
}
public long ID { get; set; }
public string Name { get; set; }
public ICollection<SegmentDto> Segment { get; set; }
}
public class SegmentDto
{
public SegmentDto()
{
}
public long ID { get; set; }
public string Serial { get; set; }
}
After a lot of fiddling around with the AfterMap() I found the UseDestinationValue option, when defined it will reuse the existing HashSet instead of replacing the ICollection with a List.
cfg.CreateMap<MachineDto, Machine>(MemberList.Source)
.ForMember(dest => dest.Segment, opt => opt.UseDestinationValue());
Related
An interesting problem of this nature. I'm trying to map List to List. That is, to compare two homogeneous objects.
However, the mapper throws me an Exception
Missing type map configuration or unsupported mapping.
I would be grateful for any help! I can't solve the problem all day.
CreateMap<List<GrammarQuestionDTO>, TestDTO>()
.ForMember(t => t.GrammarQuestion, map => map.MapFrom(source => source))
.ForAllOtherMembers(x => x.Ignore());
public class GrammarQuestionDTO
{
public int Id { get; set; }
public LevelType LevelType { get; set; }
public QuestionType QuestionType { get; set; } = QuestionType.Grammar;
public string Question { get; set; }
public List<AnswerDTO> Answers { get; set; }
}
public class TestDTO
{
public int Id { get; set; }
public List<GrammarQuestionDTO> GrammarQuestion { get; set; }
public List<AuditionQuestionDTO> AuditionQuestion { get; set; }
public string EssayTopic { get; set; }
public string SpeakingTopic { get; set; }
}
It's been a while since i've used automapper, but i'm almost sure that my situation should be possible.
Setup
I created the following mapping configuration:
var map = cfg.CreateMap<TSource, Structure>();
So in my situation the source is a generic type (unknown) and the target type is Structure (known).
A possible option for the TSource type could be:
public class DataChannel
{
public string Id { get; set; }
public string Description { get; set; }
public string Ean { get; set; }
public DateTimeOffset ValidFrom { get; set; }
public bool IsManual { get; set; }
public string Type { get; set; }
public string Unit { get; set; }
public string Address { get; set; }
public string BuildingId { get; set; }
}
The target Structure object looks like this:
public class Structure : IStructure
{
public Structure()
{
Children = new List<Structure>();
Properties = new List<StructureProperty>();
}
public int Id { get; set; }
public ICollection<StructureProperty> Properties { get; set; }
public List<Structure> Children { get; set; }
}
Situation
For example, I would like the string properties "Unit" and "Type" to be added as a StructureProperty object to the Properties collection of the Structure entity.
map.ForMember(c => c.Properties, m => m.MapFrom<StructurePropertyResolver<TSource>>());
How can this be done?
I have next enteties
public class TagDTO
{
public int Id { get; set; }
public string Description { get; set; }
public List<ImageDTO> Images { get; set; }
}
public class ImageDTO
{
public int Id { get; set; }
public List<TagDTO> Tags { get; set; }
}
And when I'm mapping from Image to ImageDTO i do not need List<Images> in TagDTO class. But in other cases this property is necessary. Can I configure in AutoMapper to Ignore List<ImagesDTO> Images, like this
CreateMap<Image, ImageDTO>().ForMember(x => x.Tags.Select(p=>p.Images),
opts => opts.Ignore());
You can see my previous question which related with many to many relation but with auto generated mapping table.
I have 2 model, HrTraining and HrPerson. Any people can be assigned to one or more Trainings. You can see my model as below
public class HrTraining
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<HrMapTrainingPerson> HrMapTrainingPerson { get; set; }
}
public class HrMapTrainingPerson
{
public int Id { get; set; }
public string Status { get; set; }
public int HrTrainingId { get; set; }
public int HrPersonId { get; set; }
public virtual HrTraining HrTraining { get; set; }
public virtual HrPerson HrPerson { get; set; }
}
public class HrPerson
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<HrMapTrainingPerson> HrMapTrainingPerson { get; set; }
}
How can i take all training objects which assingned to a person with efficient way.
So you want to find a person, and get all the trainings assigned to it? There are lot of ways.. but using your models, this could be something like this
var trPersons = dbContext.HrPerson.Find(idPerson).HrMapTrainingPerson.ToList();
foreach(var trPerson in trPersons) {
var training = trPerson.HrTraining;
//do what you want, here you can get trPerson.HrTraining.Name for instance
}
I have an Entity in Code First Entity framework that currently looks like this:
public class Entity
{
// snip ...
public string OriginalDepartment { get; set; }
public string OriginalQueue { get; set; }
public string CurrentDepartment { get; set; }
public string CurrentQueue { get; set; }
}
I would like to create Complex Type for these types as something like this:
public class Location
{
public string Department { get; set; }
public string Queue { get; set; }
}
I'd like to use this same type for both Current and Original:
public Location Original { get; set; }
public Location Current { get; set; }
Is this possible, or do I need to create two complex types CurrentLocation and OriginalLocation?
public class OriginalLocation
{
public string Department { get; set; }
public string Queue { get; set; }
}
public class CurrentLocation
{
public string Department { get; set; }
public string Queue { get; set; }
}
It is supported out of box, you do not need to create two complex types.
You can also configure your complex types explicitely with model builder
modelBuilder.ComplexType<Location>();
To customize column names, you should configure them from parent entity configuration
public class Location
{
public string Department { get; set; }
public string Queue { get; set; }
}
public class MyEntity
{
public int Id { get; set; }
public Location Original { get; set; }
public Location Current { get; set; }
}
public class MyDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.ComplexType<Location>();
modelBuilder.Entity<MyEntity>().Property(x => x.Current.Queue).HasColumnName("myCustomColumnName");
}
}
This will map MyEntity.Current.Queue to myCustomName column