I have the following entities:
public class ContactDetailsJson
{
public string Zip { get; set; }
public string Phone { get; set; }
public string AreaCode { get; set; }
public DateTime UpdatedDate { get; set; }
public string SeoContactUrl { get; set; }
public string State { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public string CompanyName { get; set; }
public string ContactUrl { get; set; }
public string Country { get; set; }
public bool Owned { get; set; }
public string City { get; set; }
public string Title { get; set; }
public string Email { get; set; }
public string Address { get; set; }
public string CompanyId { get; set; }
public string ContactId { get; set; }
}
public class ExternalContactSearchResultsViewModel
{
public int DisplayedPageNumber { get; set; }
public int TotalResultsCount { get; set; }
public int PageSize { get; set; }
public IList<ContactResultViewModel> Results { get; set; }
public class ContactResultViewModel
{
public string ContactId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Headline { get; set; }
public string Company { get; set; }
public string PublicUrl { get; set; }
public bool HasAccess { get; set; }
public DateTime LastUpdatedDate { get; set; }
}
}
To support the conversion, I have the following mappings created, which I have verified are being run:
Mapper.CreateMap<ContactDetailsJson, ExternalContactSearchResultsViewModel.ContactResultViewModel>()
.ForMember(dest => dest.Company, opt => opt.MapFrom(src => src.CompanyName))
.ForMember(dest => dest.ContactId, opt => opt.MapFrom(src => src.ContactId))
.ForMember(dest => dest.FirstName, opt => opt.MapFrom(src => src.FirstName))
.ForMember(dest => dest.LastName, opt => opt.MapFrom(src => src.LastName))
.ForMember(dest => dest.HasAccess, opt => opt.MapFrom(src => src.Owned))
.ForMember(dest => dest.Headline, opt => opt.MapFrom(src => src.Title))
.ForMember(dest => dest.LastUpdatedDate, opt => opt.MapFrom(src => src.UpdatedDate))
.ForMember(dest => dest.PublicUrl, opt => opt.Ignore());
Unfortunately, this mapping results in all properties being null (or default values), as can be seen from the following unit test
[TestMethod]
public void Automapper_Contact_Details_Json_Can_Be_Mapped()
{
// Setup
EntityMapLoader.LoadEntityMappings();
DateTime testDate = DateTime.Now;
var json = new ContactDetailsJson
{
CompanyName = "company",
ContactId = "12345",
FirstName = "first",
LastName = "last",
Owned = true,
Title = "title",
UpdatedDate = testDate
};
// Act
var result = Mapper.Map<ContactDetailsJson, ExternalContactSearchResultsViewModel.ContactResultViewModel>(json);
// Verify
Assert.IsNotNull(result, "result was null");
Assert.AreEqual("company", result.Company);
Assert.AreEqual("12345", result.ContactId);
Assert.AreEqual("first", result.FirstName);
Assert.AreEqual("last", result.LastName);
Assert.AreEqual(true, result.HasAccess);
Assert.AreEqual("title", result.Headline);
Assert.AreEqual(testDate, result.LastUpdatedDate);
}
I can't figure out what is wrong. Does anyone else see anything?
I tried this and it works for me, I think its something wrong in way you are loading mapping or check if you are using latest version of automapper
[TestFixture]
public class UnitTest
{
[Test]
public void Automapper_Contact_Details_Json_Can_Be_Mapped()
{
// Setup
DateTime testDate = DateTime.Now;
var json = new ContactDetailsJson
{
CompanyName = "company",
ContactId = "12345",
FirstName = "first",
LastName = "last",
Owned = true,
Title = "title",
UpdatedDate = testDate
};
Mapper.CreateMap<ContactDetailsJson, ExternalContactSearchResultsViewModel.ContactResultViewModel>()
.ForMember(dest => dest.Company, opt => opt.MapFrom(src => src.CompanyName))
.ForMember(dest => dest.ContactId, opt => opt.MapFrom(src => src.ContactId))
.ForMember(dest => dest.FirstName, opt => opt.MapFrom(src => src.FirstName))
.ForMember(dest => dest.LastName, opt => opt.MapFrom(src => src.LastName))
.ForMember(dest => dest.HasAccess, opt => opt.MapFrom(src => src.Owned))
.ForMember(dest => dest.Headline, opt => opt.MapFrom(src => src.Title))
.ForMember(dest => dest.LastUpdatedDate, opt => opt.MapFrom(src => src.UpdatedDate))
.ForMember(dest => dest.PublicUrl, opt => opt.Ignore());
// Act
var result = Mapper.Map<ContactDetailsJson, ExternalContactSearchResultsViewModel.ContactResultViewModel>(json);
// Verify
Assert.IsNotNull(result, "result was null");
Assert.AreEqual("company", result.Company);
Assert.AreEqual("12345", result.ContactId);
Assert.AreEqual("first", result.FirstName);
Assert.AreEqual("last", result.LastName);
Assert.AreEqual(true, result.HasAccess);
Assert.AreEqual("title", result.Headline);
Assert.AreEqual(testDate, result.LastUpdatedDate);
}
}
Related
I have 2 classses like this
public class ListOfBMTTeamMapping
{
public class TeamMapping
{
public List<TeamMappings> results { get; set; }
}
public class TeamMappings
{
public int id { get; set; }
public string areaPath { get; set; }
public string agileReleaseTrainName { get; set; }
public string deliveryTeamName { get; set; }
public string keyedInTeamCode { get; set; }
public string deliveryTeamId { get; set; }
public bool isDeleted { get; set; }
public string modified { get; set; }
public string modifiedBy { get; set; }
}
}
and next one
public class BmtAdoMapping
{
public int? Id { get; set; }
public string AreaPath { get; set; }
public string AgileReleaseTrainName { get; set; }
public string DeliveryTeamName { get; set; }
public string KeyedInTeamCode { get; set; }
public string DeliveryTeamId { get; set; }
public string IsDeleted { get; set; }
public DateTime? Modified { get; set; }
public string ModifiedBy { get; set; }
}
Here is the first class is defined to deserialize a third party API data like this
{
"results": [
{
"id": 6534,
"areaPath": "rtyty",
"agileReleaseTrainName": "rtyrty",
"deliveryTeamName": "fggfhfg",
"keyedInTeamCode": "vbnvbn",
"deliveryTeamId": 3254,
"isDeleted": false,
"modified": "2019-03-27T09:31:50.4581912",
"modifiedBy": "balassm"
},
{
"id": 6536,
"areaPath": "werwbvcbvcb",
"agileReleaseTrainName": "vbvbv",
"deliveryTeamName": "Aerere",
"keyedInTeamCode": "GTer33",
"deliveryTeamId": 3256,
"isDeleted": false,
"modified": "2019-03-27T09:31:50.4792922",
"modifiedBy": "balassm"
}
]
}
So here is my code
ListOfBMTTeamMapping.TeamMapping Results = new ListOfBMTTeamMapping.TeamMapping();
Results = JsonConvert.DeserializeObject<ListOfBMTTeamMapping.TeamMapping>(responseBody);
List<BmtAdoMapping> bmt = new List<BmtAdoMapping>();
bmt = _mapper.Map<List<BmtAdoMapping>>(Results);
Everythnig working fine and Results variable getting deserialized data. But my second class which is actually
a model class for my entity framework and on trying to map into that model class, I am getting an error like this
**AutoMapper.AutoMapperMappingException:** 'Missing type map configuration or unsupported mapping.'
Mapping types:
Object -> List`1
System.Object -> System.Collections.Generic.List`1
[[EPMO_Toolset_API.common.BmtAdoMapping, EPMO-Toolset-API, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
Here is my Automapper profile
CreateMap<ListOfBMTTeamMapping, JsonBmtAdoMapping>();
CreateMap<ListOfBMTTeamMapping.TeamMappings, JsonBmtAdoMapping>()
.ForMember(dest => dest.AgileReleaseTrainName, opt => opt.MapFrom(src => src.agileReleaseTrainName))
.ForMember(dest => dest.AreaPath, opt => opt.MapFrom(src => src.areaPath))
.ForMember(dest => dest.DeliveryTeamId, opt => opt.MapFrom(src => src.deliveryTeamId))
.ForMember(dest => dest.DeliveryTeamName, opt => opt.MapFrom(src => src.deliveryTeamName))
.ForMember(dest => dest.IsDeleted, opt => opt.MapFrom(src => src.isDeleted))
.ForMember(dest => dest.KeyedInTeamCode, opt => opt.MapFrom(src => src.keyedInTeamCode))
.ForMember(dest => dest.Modified, opt => opt.MapFrom(src => src.modified))
.ForMember(dest => dest.ModifiedBy, opt => opt.MapFrom(src => src.modifiedBy));
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 am new to automapper. I have a class that has a collection of object. And I need that class to map to another object that has a different name. I need to map the employee to employeeDto. Both classes has different name and different propery name. Can they be mapped using automapper if they have a different name?
public class Employee
{
public string Name { get; set; }
public string Address { get; set; }
public List<Job> Jobs { get; set; }
}
public class Job
{
public string CompanyName { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
public class EmployeeDto
{
public string Fullname { get; set; }
public string Location { get; set; }
public List<WorkExperience> WorkExperience { get; set; }
}
public class WorkExperience
{
public string NameOfCompany { get; set; }
public DateTime DateBegin { get; set; }
public DateTime DateEnd { get; set; }
}
You can configure mapping to handle you Jobs list to WorkExperience list manually. See Projection section in AutoMapper documentation
AutoMapper.Mapper.Initialize(cfg =>
{
cfg.CreateMap<Employee, EmployeeDto>()
.ForMember(dest => dest.Fullname, opt => opt.MapFrom(src => src.Name))
.ForMember(dest => dest.Location, opt => opt.MapFrom(src => src.Address))
.ForMember(dest => dest.WorkExperience, opt => opt.MapFrom(src => src.Jobs));
cfg.CreateMap<Job, WorkExperience>()
.ForMember(dest => dest.NameOfCompany, opt => opt.MapFrom(src => src.CompanyName))
.ForMember(dest => dest.DateBegin, opt => opt.MapFrom(src => src.StartDate))
.ForMember(dest => dest.DateEnd, opt => opt.MapFrom(src => src.EndDate));
});
Additionally, if you want to convert in the opposite direction, you can add ReverseMap() to avoid code duplication.
I am trying to map from an Entity Framework object to the DTO object, I am getting the error on the automapper profile:
The type 'ClaimToTemplateClaim' cannot be used as typed parameter
'TValueResolver' in the generic type or method
'IMemberConfigurationExpression<TemplateEntity, Template,object>.ResolveUsing<TValueResolver>()'.
There is no implicit reference conversion from 'ClaimToTemplateClaim'
to 'AutoMapper.IValueResolver<GPS.Auth2.Service.DataAccess.Objects.TemplateEntity, GPSAuth2ServiceInterface.Objects.Template, object>.'
Source Object DTO
public class Template
{
public Template()
{
this.Claims = new List<Claim>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<Claim> Claims { get; set; }
}
public class Claim
{
public int Id { get; set; }
public int ProductNumber { get; set; }
public string TheClaim { get; set; }
}
Entity Object (adds a join table)
public class TemplateEntity
{
public TemplateEntity()
{
this.TemplateClaims = new List<TemplateClaimEntity>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<TemplateClaimEntity> TemplateClaims { get; set; }
}
public class TemplateClaimEntity
{
public int TemplateId { get; set; }
public int ClaimId { get; set; }
public ClaimEntity Claim { get; set; }
public TemplateEntity Template { get; set; }
}
public class TemplateEntity
{
public TemplateEntity()
{
this.TemplateClaims = new List<TemplateClaimEntity>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
When someone passes my a claim, I need it to essentially map to a ClaimEntity object, but also create a TemplateClaimObject.
AutoMapper Profile
public Auth2SetupMappings()
{
this.CreateMap<Template, TemplateEntity>()
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
.ForMember(dest => dest.Description, opt => opt.MapFrom(src => src.Description))
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name))
.ForMember(dest => dest.TemplateClaims, opt => opt.ResolveUsing<TemplateClaimToClaim>()) <- ERROR HERE
.ReverseMap()
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
.ForMember(dest => dest.Description, opt => opt.MapFrom(src => src.Description))
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name))
.ForMember(dest => dest.Claims, opt => opt.ResolveUsing<ClaimToTemplateClaim>()); <- ERROR HERE
}
public class ClaimToTemplateClaim : IValueResolver<Claim, TemplateClaimEntity, TemplateClaimEntity>
{
public TemplateClaimEntity Resolve(Claim source, TemplateClaimEntity destination, TemplateClaimEntity member, ResolutionContext context)
{
return new TemplateClaimEntity
{
Claim = new ClaimEntity
{
Claim = source.TheClaim,
Id = source.Id,
ProductNumber = source.ProductNumber
}
};
}
}
public class TemplateClaimToClaim : IValueResolver<TemplateClaim, Claim, Claim>
{
public Claim Resolve(TemplateClaim source, Claim destination, Claim member, ResolutionContext context)
{
return new Claim
{
ProductNumber = source.Claim.ProductNumber,
Id = source.Claim.Id,
TheClaim = source.Claim.TheClaim
};
}
}
Essentially we do not want to pass the join table to the DTO.
I've been trying to use AutoMapper, but I'am having trouble configuring the map.
Having this:
public class A
{
public B b { get; set; }
public C c { get; set; }
public int id { get; set; }
public string X { get; set; }
}
public class B
{
public int id { get; set; }
public string Y { get; set; }
}
public class C
{
public int id { get; set; }
public string Z { get; set; }
}
public class ABC
{
public int Aid { get; set; }
public string AX { get; set; }
public int Bid { get; set; }
public string BY { get; set; }
public int Cid { get; set; }
public string CZ { get; set; }
}
How can I do mapping A > ABC and ABC > A.
I don't want to map each property manually. Is it possible?
Thank you.
I am not sure what you mean by "I don't want to map each property manually". But with AutoMapper you could easily map the properties:
Mapper.Initialize(cfg => cfg.CreateMap<A, ABC>()
.ForMember(dest => dest.AX, opt => opt.MapFrom(src => src.X))
.ForMember(dest => dest.Aid, opt => opt.MapFrom(src => src.id))
.ForMember(dest => dest.BY, opt => opt.MapFrom(src => src.b.Y))
.ForMember(dest => dest.Bid, opt => opt.MapFrom(src => src.b.id))
.ForMember(dest => dest.CZ, opt => opt.MapFrom(src => src.c.Z))
.ForMember(dest => dest.Cid, opt => opt.MapFrom(src => src.c.id)));
var a = new A
{
X = "I am A",
id = 0,
b = new B()
{
Y = "I am B",
id = 1
},
c = new C()
{
Z = "I am C",
id = 2
}
};
var abc = Mapper.Map<A, ABC>(a);