I have 2 class Data and MainData that I need to map
public class Data
{
public Field<string> Results { get; set; }
public Field<int> A { get; set; }
public Field<int> B { get; set; }
}
public class Field<T>
{
public string Label { get; set; }
public T Value { get; set; }
}
public class MainData{
public string result {get; set; }
public int a {get; set; }
public int b {get; set; }
}
I've tried to map Data to MainData using automapper as follows:
Mapper.CreateMap(Data, MainData))
.ForMember(dest => dest.result, conf => conf.MapFrom(src => src.results.Value))
.ForMember(dest => dest.a, conf => conf.MapFrom(src => src.A.Value))
.ForMember(dest => dest.b, conf => conf.MapFrom(src => src.B.Value))
var destination = Mapper.Map<Data, MainData>(source);
It's never get mapped value to desination variable. All i get is new MainData object.
Related
I have this function in my controller that creates a an entity:
[HttpPost]
[ProducesResponseType(typeof(ConnectionDBResponse), StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<ConnectionDBResponse>> PostConnectionDB([FromBody] CreateConnectionDBQuery query)
{
var connectionDBs = _mapper.Map<ConnectionDBDataModel>(query);
_context.ConnectionDB.Add(connectionDBs);
await _context.SaveChangesAsync();
var connectionDBResponse = _mapper.Map<ConnectionDBResponse>(connectionDBs);
return CreatedAtAction(nameof(GetAllConnectionDB), new { id = connectionDBs.Id }, connectionDBResponse);
}
For that I'm mapping between these two classes:
The response Class:
public class CreateConnectionDBQuery
{
public string ServerType { get; set; }
public string ServerName { get; set; }
public string port { get; set; }
public string AuthType { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string DBName { get; set; }
public string FolderName { get; set; }
public ScheduleConfigResponse ScheduleConfig { get; set; }
public Boolean hasEmails { get; set; }
public EmailConfigResponse EmailConfig { get; set; }
}
public class CreateScheduleConfigQuery
{
public string HourOfSave { get; set; }
public int NumDaysInDB { get; set; }
public CreateConnectionDBQuery ConnDB { get; set; }
public int ConnDBForeignKey { get; set; }
}
public class CreateEmailConfigQuery
{
public string SuccesEmail { get; set; }
public string FailureEmail { get; set; }
public CreateConnectionDBQuery ConnDB { get; set; }
public int ConnDBForeignKey { get; set; }
}
And the dataModel Class:
[Table("ConnectionDB")]
public class ConnectionDBDataModel
{
[Key]
public int Id { get; set; }
[Required]
public string ServerType { get; set; }
[Required]
public string ServerName { get; set; }
public string port { get; set; }
public string AuthType { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
[Required]
public string DBName { get; set; }
[Required]
public string FolderName { get; set; }
public ScheduleConfigDataModel ScheduleConfig { get; set; }
public Boolean hasEmails { get; set; }
public EmailConfigDataModel EmailConfig { get; set; }
}
[Table("ScheduleConfig")]
public class ScheduleConfigDataModel
{
[Key]
public int Id { get; set; }
public string HourOfSave { get; set; }
public int NumDaysInDB { get; set; }
public int ConnDBForeignKey { get; set; }
public ConnectionDBDataModel ConnDB { get; set; }
}
[Table("EmailConfig")]
public class EmailConfigDataModel
{
[Key]
public int Id { get; set; }
public string SuccesEmail { get; set; }
public string FailureEmail { get; set; }
public int ConnDBForeignKey { get; set; }
public ConnectionDBDataModel ConnDB { get; set; }
}
For that I'm using the AutoMapper as following:
#region ConnectionDB
CreateMap<ConnectionDBDataModel, ConnectionDBResponse>();
CreateMap<CreateConnectionDBQuery, ConnectionDBDataModel>()
.ForMember(dest => dest.Id, opt => opt.Ignore());
CreateMap<UpdateConnectionDBQuery, ConnectionDBDataModel>()
.ForMember(dest => dest.Id, opt => opt.Ignore());
#endregion
#region ScheduleConfig
CreateMap<ScheduleConfigDataModel, ScheduleConfigResponse>()
.ForMember(dest => dest.ConnDBForeignKey, opt => opt.Ignore());
CreateMap<CreateScheduleConfigQuery, ScheduleConfigDataModel>()
.ForMember(dest => dest.Id, opt => opt.Ignore())
.ForMember(dest => dest.ConnDBForeignKey, opt => opt.Ignore());
CreateMap<UpdateScheduleConfigQuery, ScheduleConfigDataModel>()
.ForMember(dest => dest.Id, opt => opt.Ignore());
#endregion ScheduleConfig
#region EmailConfig
CreateMap<EmailConfigDataModel, EmailConfigResponse>()
.ForMember(dest => dest.ConnDBForeignKey, opt => opt.Ignore());
CreateMap<CreateEmailConfigQuery, EmailConfigDataModel>()
.ForMember(dest => dest.Id, opt => opt.Ignore())
.ForMember(dest => dest.ConnDBForeignKey, opt => opt.Ignore());
CreateMap<UpdateEmailConfigQuery, EmailConfigDataModel>()
.ForMember(dest => dest.Id, opt => opt.Ignore());
#endregion
But when I try to create this element it gives me an error saying that it's coming from an invalid Mapping as shown in the screen bellow:
I have tried to Ignore the Foreign Key (because my guess that this problem is coming from the foreignKey) using this line of code : .ForMember(dest => dest.ConnDBForeignKey, opt => opt.Ignore()); , but I guess it's not the way to solve that problem.
Any help would be appreciated thank you!
The error is happening because when mapping CreateConnectionDBQuery to ConnectionDBDataModel, there is no mapping defined for the types of the ScheduleConfig properties.
I'm guessing that in your CreateConnectionDBQuery, your ScheduleConfig property should be of type CreateScheduleConfigQuery instead of ScheduleConfigResponse.
Alternatively, if you don't want to change the models, you could add a mapping configuration from ScheduleConfigResponse to ScheduleConfigDataModel. But that doesn't seem very intuitive.
I have four classes
public class Status
{
public long Key { get; set; }
public string DisplayString { get; set; }
}
public class Attachment
{
public long Key { get; set; }
public string FileName { get; set; }
public long FileSize { get; set; }
public string ExternalKey_SO { get; set; }
}
public class TaskClick
{
public long Key { get; set; }
public string CallId { get; set; }
public Status Status { get; set; }
public List<Attachment> Attachments { get; set; }
}
public class TaskClickDto
{
public long Key { get; set; }
public string CallId { get; set; }
public string Status { get; set; }
public List<long> AttachmentKeys { get; set; }
}
I donĀ“t know how to map a list of TaskClickDto.AttachmentKeys to TaskClick.Attachments
AttachmentKeys is a list of all the Keys of Taskclick
My automapper configuration
public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
CreateMap<TaskClick, TaskClickDto>()
//TaskClick --> TaskClickDto works ok
.ForMember(dest => dest.CallId, opt => opt.MapFrom(src => src.CallId))
.ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.Status.DisplayString))
.ForMember(dest => dest.AttachmentKeys, opt => opt.MapFrom(src => src.Attachments.Select(k => k.Key)))
.ReverseMap()
//TaskClickDto --> TaskClick works Ko
.ForPath(dest => dest.Status.DisplayString, opt => opt.MapFrom(src => src.Status))
.ForPath(dest => dest.Attachments, ????));
}
}
So I need to know how to create a new list of Attachment , for each one, map the key and ignore the rest of the properties.
Best regards.
jolynice
This should do it:
.ForPath(dest => dest.Attachments, opt =>
opt.MapFrom(src => src.AttachmentKeys.Select(k =>
new Attachment { Key = k }).ToList()));
I want to combine 2 Domain Objects into a single data transfer object using AutoMapper.
Domain Model:
public class Service {
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<DownloadService> DownloadServices { get; set; } = new HashSet<DownloadService>();
}
public class DownloadService {
public int Id { get; set; }
public int PageLimit { get; set; }
public virtual int ServiceId { get; set; }
public virtual Service Service { get; set; }
}
public class Volume {
public override int Id { get; set; }
public bool IsActive { get; set; }
public string Path { get; set; }
public string Description { get; set; }
}
DTO:
public class PreferenceVM {
public ICollection<VolumeVM> Volumes { get; set; }
public ICollection<ServiceVM> Services { get; set; }
}
public class ServiceVM {
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<DownloadServiceVM> DownloadServices { get; set; } = new HashSet<DownloadServiceVM>();
}
public class DownloadServiceVM {
public int Id { get; set; }
public int PageLimit { get; set; }
public int CleaningInterval { get; set; }
}
public class VolumeVM {
public int Id { get; set; }
public bool IsActive { get; set; }
public string Path { get; set; }
public string Description { get; set; }
}
Mapping:
cfg.CreateMap<Volume, VolumeVM>().ReverseMap();
cfg.CreateMap<DownloadService, DownloadServiceVM>().ReverseMap();
cfg.CreateMap<Service, ServiceVM>()
.ForMember(d => d.DownloadServices, opt => opt.MapFrom(s => s.DownloadServices))
.ReverseMap();
cfg.CreateMap<ICollection<Volume>, PreferenceVM>()
.ForMember(x => x.Volumes, y => y.MapFrom(src => src)).ReverseMap();
cfg.CreateMap<ICollection<Service>, PreferenceVM>()
.ForMember(x => x.Services, y => y.MapFrom(src => src)).ReverseMap();
when I try the mapping above:
var services = serviceRepository.GetAll();
var volumes = volumeRepository.GetAll();
var entities = mapper.Map<PreferenceVM>(services);
entities = mapper.Map(volumes, entities);
I get the following errors:
Missing type map configuration or unsupported mapping.
Mapping types: EntityQueryable1 -> PreferenceVM
Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable1[[Fwims.Core.Data.Model.Setting.Service,
Fwims.Core.Data.Model, Version=1.0.1.10, Culture=neutral,
PublicKeyToken=null]] -> Fwims.Core.ViewModel.Setting.PreferenceVM
It looks like my mapping is wrong, nothing I have tried has worked. How do I properly map the Domain objects to the Data transfer objects?
Here
cfg.CreateMap<ICollection<Volume>, PreferenceVM>()
.ForMember(x => x.Volumes, y => y.MapFrom(src => src)).ReverseMap();
and
cfg.CreateMap<ICollection<Service>, PreferenceVM>()
.ForMember(x => x.Services, y => y.MapFrom(src => src)).ReverseMap();
you create mappings from ICollection<TSource>.
However later on you are trying to map IQeryable<TSource>. While AutoMapper can use a base mapping to map a derived class, IQueryable<T> does not derive from ICollection<T>, hence the missing type map exception.
The solution is to create a mapping from some common base interface of IQueryable<T> and ICollection<T>, which is IEnumerable<T>.
So replace the above with:
cfg.CreateMap<IEnumerable<Volume>, PreferenceVM>()
.ForMember(x => x.Volumes, y => y.MapFrom(src => src));
cfg.CreateMap<IEnumerable<Service>, PreferenceVM>()
.ForMember(x => x.Services, y => y.MapFrom(src => src));
and the current issue will be solved.
Note that ReverseMap does not work in such scenarios, so I've just removed it. If you need such functionality, you have to create that mappings manually (eventually using ConvertUsing because there is no destination member).
I need a help from you ...
I'm developing a solution using the Cassandra Data Base and DataStax driver for C# to generate POCO code to generate the column family to the database, the problem is that I'm mapping wanting to map a column that is a UDT dictionary and is not operating, below the code so that someone can help me ...
Maps.cs
For<Users>()
.TableName("Users")
.PartitionKey(key => key.UsersId)
.Column(u => u.UsersId, map => map.WithName("UsersId"))
.Column(u => u.ImgProfileUrl, map => map.WithName("ImgProfileUrl"))
.Column(u => u.Name, map => map.WithName("Name"))
.Column(u => u.Gender, map => map.WithName("Gender"))
.Column(u => u.UserName, map => map.WithName("UserName"))
.Column(u => u.UserPassword, map => map.WithName("UserPassword"))
.Column(u => u.DateOfBorn, map => map.WithName("DateOfBorn"))
.Column(u => u.OpeningDate, map => map.WithName("OpeningDate"))
.Column(u => u.FederalRegistrationCode, map => map.WithName("FederalRegistrationCode"))
.Column(u => u.StateRegistrationCode, map => map.WithName("StateRegistrationCode"))
.Column(u => u.TownRegistrationCode, map => map.WithName("TownRegistrationCode"))
.Column(u => u.Score, map => map.WithName("Score"))
.Column(u => u.Type, map => map.WithName("Type"))
.Column(u => u.Status, map => map.WithName("Status"))
.Column(u => u.DateOfCreated, map => map.WithName("DateOfCreated"))
.Column(u => u.Tags, map => map.WithName("Tags"))
.Column(u => u.Contacts, map => map.AsFrozen());
Entities Column Family
public class Users
{
public Guid UsersId { get; set; }
public string Name { get; set; }
public string ImgProfileUrl { get; set; }
public string UserName { get; set; }
public string UserPassword { get; set; }
public int? Gender { get; set; }
public DateTime? DateOfBorn { get; set; }
public DateTime? OpeningDate { get; set; }
public int Status { get; set; }
public string FederalRegistrationCode { get; set; }
public string StateRegistrationCode { get; set; }
public string TownRegistrationCode { get; set; }
public int Type { get; set; }
public int Score { get; set; }
public DateTime DateOfCreated { get; set; }
public IEnumerable<string> Tags { get; set; }
public IEnumerable<contactsudt> Contacts { get; set; }
}
Entities UDT
public class contactsudt
{
public string Phone { get; set; }
public string Celular { get; set; }
public string Address { get; set; }
public long Number { get; set; }
public string District { get; set; }
public string Postalcode { get; set; }
public string Name { get; set; }
public string State { get; set; }
public string Country { get; set; }
}
Configuration Instance
new Configuration<contactsudt, Users>();
new Table<Users>(UtilsDb.Session).CreateIfNotExists();
Make sure that you're registering your UDT with the session object whenever you bootstrap/create the session before you try to use it. For example, to use auto-mapping:
session.UserDefinedTypes.Define(
UdtMap.For<contactsudt>()
.Automap()
);
Also, make sure to register your maps (in Maps.cs in the example you gave) with the global MappingConfiguration so that LINQ will know about it:
MappingConfiguration.Global.Define<Maps>();
It sounds like you're probably missing the user defined type map.
Suppose in the source object I have classes:
// Source classes
class Source
{
public Source
{
things = new List<Thing>();
}
public Guid SourceId { get; set; }
public string Name { get; set; }
public virtual List<Thing> Things { get; set; }
}
class Thing
{
public Guid ThingId { get; set; }
public double Price { get; set; }
}
//Destination class
class Dest
{
public Guid DestId { get; set; }
public string Name { get; set; }
public virtual List<Guid> ThingsIds { get; set; }
}
How do I map Things -> ThingId (src) to ThingsIds (dest) using Automapper?
I would use the LINQ extension method .Select:
Mapper.CreateMap<Source, Dest>()
.ForMember(
dest => dest.ThingsIds,
opt => opt.MapFrom(src => src.Things.Select(th => th.ThingId)));