Automapper is mapping incorrectly? - automapper

I have two objects, Project is a DB entity and IProject which I am trying to save to the database:
public interface IProject
{
int ProjectID { get; set; }
string JobNumber { get; set; }
string JobName { get; set; }
string ProjectLocation { get; set; }
int? FeeTypeID { get; set; }
decimal? Fee { get; set; }
decimal? ConstructionCost { get; set; }
decimal? CostPerSquareFoot { get; set; }
decimal? SquareFoot { get; set; }
string Memo { get; set; }
DateTime? DateCompleted { get; set; }
int JobStatusID { get; set; }
int ProjectTypeID { get; set; }
}
//The inheritance is actually in a partial class that doesn't get overridden
public partial class Project : IProject
{
public Project()
{
this.ProjectContacts = new HashSet<ProjectContact>();
this.ProjectConsultants = new HashSet<ProjectConsultant>();
}
public int ProjectID { get; set; }
public string JobNumber { get; set; }
public string JobName { get; set; }
public Nullable<int> FeeTypeID { get; set; }
public Nullable<decimal> Fee { get; set; }
public int JobStatusID { get; set; }
public string Memo { get; set; }
public Nullable<decimal> Acreage { get; set; }
public Nullable<decimal> SquareFoot { get; set; }
public Nullable<decimal> ConstructionCost { get; set; }
public Nullable<decimal> BudgetPrice { get; set; }
public Nullable<decimal> ActualPrice { get; set; }
public Nullable<System.DateTime> DateCompleted { get; set; }
public Nullable<decimal> CostPerSquareFoot { get; set; }
public string ProjectLocation { get; set; }
public int ProjectTypeID { get; set; }
public Nullable<System.DateTime> StartDate { get; set; }
public Nullable<int> PhaseID { get; set; }
public string ProjectDescription { get; set; }
public Nullable<int> ArchitectID { get; set; }
public Nullable<int> ManagerID { get; set; }
public Nullable<int> ArchiveLocationID { get; set; }
public virtual ICollection<ProjectContact> ProjectContacts { get; set; }
public virtual FeeType FeeType { get; set; }
public virtual JobStatu JobStatu { get; set; }
public virtual ICollection<ProjectConsultant> ProjectConsultants { get; set; }
public virtual Person Person { get; set; }
public virtual ArchiveLocation ArchiveLocation { get; set; }
public virtual Person Person1 { get; set; }
public virtual Phase Phase { get; set; }
public virtual ProjectType ProjectType { get; set; }
}
I have my Map created:
Mapper.CreateMap<IProject, Data.Project>();
but for some reason whenever I call the map:
//mappingService is a wrapper I have around Automapper so that I can inject it
var project = _mappingService.Map<IProject, Data.Project>(request);
I get this error:
Missing type map configuration or unsupported mapping.
Mapping types:
RuntimeType -> FeeType
System.RuntimeType -> Renaissance.Data.FeeType
Destination path:
Project.FeeType.FeeType
Source value:
System.Decimal
I am not at any point trying to do that. The names match and even if I specifically tell it to map with:
.ForMember(dest => dest.Fee, opt => opt.MapFrom(src => src.Fee))
It still errors with the same message.
What am I missing?
UPDATE
This works:
.ForMember(dest => dest.FeeType, opt => opt.Ignore());
I think it is a hack that I need to do that. I shouldn't have to ignore a property in the destination that does not exist / is not named the same as something in the source property.

Related

Configuring AutoMapper in ASP.NET Core

I am trying to use automapper 8.0.0 to fill a list of WorkViewModel.
This list is getting data from the Work class out of the database using entity framework.
How ever it looks like something is going wrong with initializing as throwing follows error:
InvalidOperationException: Mapper not initialized
What am I doing wrong?
I have setup the following code!
Startup.cs
services.AddAutoMapper();
Function being called:
public async Task<IEnumerable<WorkViewModel>> GetAllAsync()
{
IList<Work> works = await _context.Work.ToListAsync();
IList<WorkViewModel> viewModelList = Mapper.Map<IList<Work>, IList<WorkViewModel>>(works);
return viewModelList;
}
Configuration:
public class MappingProfile : Profile
{
public MappingProfile()
{
Mapper.Initialize(cfg =>
{
cfg.CreateMap<WorkViewModel, Work>();
});
}
}
WorkViewModel:
public class WorkViewModel
{
public int WorkID { get; set; }
public string Name { get; set; }
public byte[] Tumbmail { get; set; }
public string Discription { get; set; }
public string Client { get; set; }
public DateTime Date { get; set; }
public string PreviewLink { get; set; }
public string GitLink { get; set; }
public string DownloadLink { get; set; }
public int DetailID { get; set; }
public byte[] Banner { get; set; }
public string Documentation { get; set; }
public int CategoryID { get; set; }
public string Category { get; set; }
}
Work Model:
public class Work
{
[Key]
public int WorkID { get; set; }
[Display(Name = "Project Name")]
public string Name { get; set; }
[Display(Name = "Client name")]
public string Client { get; set; }
[Display(Name = "Description")]
public string Discription { get; set; }
[Display(Name = "Date")]
public DateTime Date { get; set; }
[Display(Name = "Thumbmail")]
public byte[] Tumbmail { get; set; }
[Display(Name = "Preview Link")]
public string PreviewLink { get; set; }
[Display(Name = "Git Link")]
public string GitLink { get; set; }
[Display(Name = "DownloadLink")]
public string DownloadLink { get; set; }
public WorkCategory workCategory { get; set; }
public WorkDetailed WorkDetailed { get; set; }
}
Only adding services.AddAutoMapper(); to the ConfigureServices method would not work for you. You have to configure AutoMapper as follows:
public void ConfigureServices(IServiceCollection services)
{
// Auto Mapper Configurations
var mappingConfig = new MapperConfiguration(mc =>
{
mc.AddProfile(new MappingProfile());
});
IMapper mapper = mappingConfig.CreateMapper();
services.AddSingleton(mapper);
services.AddMvc();
}
And also don't forget to install the AutoMapper.Extensions.Microsoft.DependencyInjection nuget package.

Need Help Displaying The Name Instead of a GUID in a DataTable in MVC 5

I need some help displaying the name instead of a GUID inside a DataTable in MVC 5.
I implemented the DataTable by following this tutorial: https://www.c-sharpcorner.com/article/ajax-crud-operation-with-jquery-datatables-in-asp-net-mvc-5-for-beginners/
I am trying to show the names for a Municipal Region, Municipality and Client Status. It shows perfectly fine inside my details view model, however it displays the GUID in the DataTable. I have spent days trying to figure this out to no avail.
Here is the code for the DataTable in my controller:
public ActionResult Get([ModelBinder(typeof(DataTablesBinder))] IDataTablesRequest requestModel, ClientsAdvancedSearchViewModel searchViewModel)
{
IQueryable<Client> query = DbContext.Clients;
var totalCount = query.Count();
// searching and sorting
query = SearchClients(requestModel, searchViewModel, query);
var filteredCount = query.Count();
// Paging
query = query.Skip(requestModel.Start).Take(requestModel.Length);
var data = query.Select(client => new
{
ClientIdentifier = client.ClientIdentifier,
CompanyName = client.CompanyName,
ClientContactPerson = client.ClientContactPerson,
ClientEmail = client.ClientEmail,
ClientTel = client.ClientTel,
Consultant = client.Consultant,
Town = client.Town,
Suburb = client.Suburb,
MunicipalRegionID = client.MunicipalRegionID,
MunicipalityID = client.MunicipalityID,
ClientStatusID = client.ClientStatusID,
}).ToList();
return Json(new DataTablesResponse(requestModel.Draw, data, filteredCount, totalCount), JsonRequestBehavior.AllowGet);
}
And here is the code for my client class:
public class Client
{
[Key]
public System.Guid ClientIdentifier { get; set; }
public string CompanyName { get; set; }
public string SiteName { get; set; }
public string Status { get; set; }
public string Consultant { get; set; }
public string Comments { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public Nullable<System.DateTime> Date { get; set; }
public string ClientInformation { get; set; }
public string ClientContactPerson { get; set; }
public string ClientEmail { get; set; }
public string ClientTel { get; set; }
public string ClientAddress { get; set; }
public string GPSCoordinates { get; set; }
public string Town { get; set; }
public string Suburb { get; set; }
public System.Guid MunicipalRegionID { get; set; }
public System.Guid MunicipalityID { get; set; }
public System.Guid ClientStatusID { get; set; }
public string CreatedBy { get; set; }
public Nullable<System.DateTime> DateCreated { get; set; }
public string LastEditedBy { get; set; }
public Nullable<System.DateTime> DateLastEdited { get; set; }
}
Here is the code for my Municipal Region Class:
public class MunicipalRegion
{
[Key]
public System.Guid MunicipalRegionIdentifier { get; set; }
public string MunicipalRegionName { get; set; }
public string CreatedBy { get; set; }
public Nullable<System.DateTime> DateCreated { get; set; }
public string LastEditedBy { get; set; }
public Nullable<System.DateTime> DateLastEdited { get; set; }
}
Here is the code for my Municipality Class:
public class Municipality
{
[Key]
public System.Guid MunicipalityIdentifier { get; set; }
public string MunicipalityName { get; set; }
public System.Guid MunicipalRegionID { get; set; }
public string CreatedBy { get; set; }
public Nullable<System.DateTime> DateCreated { get; set; }
public string LastEditedBy { get; set; }
public Nullable<System.DateTime> DateLastEdited { get; set; }
Here is the code for my Client Status Class:
public class ClientStatus
{
[Key]
public System.Guid ClientStatusIdentifier { get; set; }
public string ClientStatusName { get; set; }
public string CreatedBy { get; set; }
public Nullable<System.DateTime> DateCreated { get; set; }
public string LastEditedBy { get; set; }
public Nullable<System.DateTime> DateLastEdited { get; set; }
}
Help would be appreciated. Thank you :)
I may be wrong but it sounds like you are trying to hide the key fields from generated views. This can be accomplished adding the following annotation.
[Display(AutoGenerateField=false)]
Ok, I see what you are trying to do now. The main problem is your classes are not set up correctly. From a database perspective they are correct but from a class perspective, they won't return what you want.
You need to set up your classes as follows
Client Class
public Client()
{
Municipality = new Municipality();
Status = new ClientStatus();
}
[Key]
public System.Guid ClientIdentifier { get; set; }
public string CompanyName { get; set; }
public string SiteName { get; set; }
public string Consultant { get; set; }
public string Comments { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public Nullable<System.DateTime> Date { get; set; }
public string ClientInformation { get; set; }
public string ClientContactPerson { get; set; }
public string ClientEmail { get; set; }
public string ClientTel { get; set; }
public string ClientAddress { get; set; }
public string GPSCoordinates { get; set; }
public string Town { get; set; }
public string Suburb { get; set; }
public string CreatedBy { get; set; }
public Nullable<System.DateTime> DateCreated { get; set; }
public string LastEditedBy { get; set; }
public Nullable<System.DateTime> DateLastEdited { get; set; }
// Create Forign Key Connections
public Municipality Municipality { get; set; }
public ClientStatus Status { get; set; }
}
Municipality Class
public class Municipality
{
public Municipality() {
MunicipalRegion = new MunicipalRegion();
}
[Key]
public System.Guid MunicipalityIdentifier {
get;
set;
}
public string MunicipalityName { get; set; }
public string CreatedBy { get; set; }
public Nullable<System.DateTime> DateCreated { get; set; }
public string LastEditedBy { get; set; }
public Nullable<System.DateTime> DateLastEdited { get; set; }
public MunicipalRegion MunicipalRegion { get; set; }
}
This will allow you to produce output using something similar to
var data = clients.Select(cl => new
{
ClientIdentifier = cl.ClientIdentifier,
CompanyName = cl.CompanyName,
MunicipalRegion = cl.Municipality.MunicipalityName,
Status = cl.Status.ClientStatusName
});

Automapper to map child tables

I have 3 tables in my database and these are the classes:
public class PRAT
{
public PRAT()
{
PRAT_RIC = new HashSet<PRAT_RIC>();
}
public int ID { get; set; }
public string PRATICA { get; set; }
public int ANNO { get; set; }
public string VARIANTE { get; set; }
[...] other fields
}
public class PRAT_RIC
{
public int ID { get; set; }
public int IDPRAT { get; set; }
public int IDANAG { get; set; }
public int? IDTITRIC { get; set; }
public virtual ANAGRAFI IDANAGNavigation { get; set; }
}
public class ANAGRAFI
{
public int ID { get; set; }
public string TIPO { get; set; }
public string TITOLO { get; set; }
public string COGNOME { get; set; }
public string NOME { get; set; }
public string CODFISC { get; set; }
}
So, the relations are:
Prat -> Prat_Ric (Prat.Id=Prat_Ric.IdPrat) -> Anagrafi (Anagrafi.Id=Prat_Ric.IdAnag)
These are the destination classes:
public class PraticaResource
{
public int ID { get; set; }
public string PRATICA { get; set; }
public int ANNO { get; set; }
public string VARIANTE { get; set; }
public ICollection<RichiedentiResource> RICHIEDENTI { get; set; }
}
public class RichiedentiResource
{
public int ID { get; set; }
public int IDANAG { get; set; }
public string TITOLO { get; set; }
public string COGNOME { get; set; }
public string NOME { get; set; }
public string CODFISC { get; set; }
public string TITRIC { get; set; }
}
I created the map with
CreateMap<PRAT_RIC, RichiedentiResource>()
.ForMember(p => p.COGNOME, opt => opt.MapFrom(ti => ti.IDANAGNavigation.COGNOME))
.ForMember(p => p.NOME, opt => opt.MapFrom(ti => ti.IDANAGNavigation.NOME));
Is it possible to map all the properties of RichiedentiResource to the ANAGRAFI fields with the same name so that i haven't to write every single field mapping?
Thank you.
If you don't need anything from the navigation class, then you can just skip it when mapping at the top level:
CreateMap<PRAT, PraticaResource>()
.ForMember(p => p.PRAT_RIC, opt => opt.MapFrom(src => src.PRAT_RIC.Select(x => x.IDANAGNavigation))
Then you just need the mapping from ANAGRAFI -> RichiedentiResource, which should work out the field mappings automatically.

ServiceStack ORMLite - Can't Infer Relationship (because of DTO name?)

I am modeling a service business that performs multiple services at each visit to a client. I have a Visit table, a Service table and a link table, VisitService. I am using this Request DTO in my service to get a list of services for a visit:
[Route("/visits/{visitid}/services", Verbs = "GET")]
public class ServicesAtVisit : QueryBase<VisitService, ServiceAtVisit>, IJoin<VisitService, My.Namespace.Service> {
public int VisitId { get; set; }
}
ServiceAtVisit is a custom DTO that I'm projecting into.
Because one of my DTOs is a class with the unfortunate name "Service", I have to fully-qualify it in the IJoin because, otherwise, it is ambiguous with ServiceStack.Service. Now, when I hit the route, I get the error "Could not infer relationship between VisitService and Service".
The interesting thing is that I've got this working with other many-to-many relationships (Client.AssignedStaffMembers, StaffMember.AssignedClients for the tables Client -> ClientStaffMember -> StaffMember) and I can't see anything different.
Is the problem the name of my DTO and the fact that I'm having to fully-qualify it?
Visit:
[Route("/visits", Verbs = "POST")]
public partial class Visit {
[AutoIncrement]
public long Id { get; set; }
public int ServiceRequestId { get; set; }
public string TimeOfDay { get; set; }
public DateTime Date { get; set; }
public TimeSpan? PreferredStartTime { get; set; }
public TimeSpan? PreferredEndTime { get; set; }
public bool IsFirstVisit { get; set; }
public bool IsLastVisit { get; set; }
public bool IncursWeekendFee { get; set; }
public bool WaiveWeekendFee { get; set; }
public bool IncursHolidayFee { get; set; }
public bool WaiveHolidayFee { get; set; }
public bool IncursLastMinuteSchedulingFee { get; set; }
public bool WaiveLastMinuteSchedulingFee { get; set; }
public bool IncursLastMinuteCancellationFee { get; set; }
public bool WaiveLastMinuteCancellationFee { get; set; }
public int? StaffMemberId { get; set; }
public string Notes { get; set; }
public bool IsCancelled { get; set; }
public DateTime? CheckInDateTime { get; set; }
public int? CheckInStaffMemberId { get; set; }
public DateTime? CheckOutDateTime { get; set; }
public int? CheckOutStaffMemberId { get; set; }
[Ignore]
public ServiceRequest ServiceRequest { get; set; }
[Ignore]
public StaffMember StaffMember { get; set; }
[Ignore]
public List<ServiceAtVisit> ServicesAtVisit { get; set; }
}
VisitService:
public partial class VisitService {
// Workaround for composite key limitation
public string Id {
get {
return this.VisitId.ToString() + "|" + this.ServiceId.ToString();
}
}
public long VisitId { get; set; }
public int ServiceId { get; set; }
public int Quantity { get; set; }
public bool FeeIsWaived { get; set; }
[Ignore]
public Visit Visit { get; set; }
[Ignore]
public Service Service { get; set; }
}
Service:
public partial class Service {
[AutoIncrement]
public int Id { get; set; }
public int ServiceTypeId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int DisplayOrder { get; set; }
public bool IsHourly { get; set; }
public bool IsMonthly { get; set; }
[Ignore]
public ServiceType ServiceType { get; set; }
[Ignore]
public ServicePrice CurrentPrice { get; set; }
}
Projecting results into ServiceAtVisit:
public partial class ServiceAtVisit {
public int ServiceTypeId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int DisplayOrder { get; set; }
public bool IsHourly { get; set; }
public bool IsMonthly { get; set; }
public int VisitId { get; set; }
public int ServiceId { get; set; }
public int Quantity { get; set; }
public bool FeeIsWaived { get; set; }
}
I've just tried creating an AutoQuery Service with all the types you've provided under a custom MyNamespace and it's working as expected (in the latest of ServiceStack), i.e:
Service definition:
namespace MyNamespace
{
[Route("/visits/{VisitId}/services", Verbs = "GET")]
public class ServicesAtVisit : QueryBase<VisitService, ServiceAtVisit>,
IJoin<VisitService, Service>
{
public int VisitId { get; set; }
}
public partial class ServiceAtVisit
{
public int ServiceTypeId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int DisplayOrder { get; set; }
public bool IsHourly { get; set; }
public bool IsMonthly { get; set; }
public int VisitId { get; set; }
public int ServiceId { get; set; }
public int Quantity { get; set; }
public bool FeeIsWaived { get; set; }
}
}
Type definition:
namespace MyNamespace
{
[Route("/visits", Verbs = "POST")]
public partial class Visit
{
[AutoIncrement]
public long Id { get; set; }
public int ServiceRequestId { get; set; }
public string TimeOfDay { get; set; }
public DateTime Date { get; set; }
public TimeSpan? PreferredStartTime { get; set; }
public TimeSpan? PreferredEndTime { get; set; }
public bool IsFirstVisit { get; set; }
public bool IsLastVisit { get; set; }
public bool IncursWeekendFee { get; set; }
public bool WaiveWeekendFee { get; set; }
public bool IncursHolidayFee { get; set; }
public bool WaiveHolidayFee { get; set; }
public bool IncursLastMinuteSchedulingFee { get; set; }
public bool WaiveLastMinuteSchedulingFee { get; set; }
public bool IncursLastMinuteCancellationFee { get; set; }
public bool WaiveLastMinuteCancellationFee { get; set; }
public int? StaffMemberId { get; set; }
public string Notes { get; set; }
public bool IsCancelled { get; set; }
public DateTime? CheckInDateTime { get; set; }
public int? CheckInStaffMemberId { get; set; }
public DateTime? CheckOutDateTime { get; set; }
public int? CheckOutStaffMemberId { get; set; }
//[Ignore]
//public ServiceRequest ServiceRequest { get; set; }
//[Ignore]
//public StaffMember StaffMember { get; set; }
[Ignore]
public List<ServiceAtVisit> ServicesAtVisit { get; set; }
}
public partial class VisitService
{
// Workaround for composite key limitation
public string Id
{
get
{
return this.VisitId.ToString() + "|" + this.ServiceId.ToString();
}
}
public long VisitId { get; set; }
public int ServiceId { get; set; }
public int Quantity { get; set; }
public bool FeeIsWaived { get; set; }
[Ignore]
public Visit Visit { get; set; }
[Ignore]
public Service Service { get; set; }
}
public partial class Service
{
[AutoIncrement]
public int Id { get; set; }
public int ServiceTypeId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int DisplayOrder { get; set; }
public bool IsHourly { get; set; }
public bool IsMonthly { get; set; }
//[Ignore]
//public ServiceType ServiceType { get; set; }
//[Ignore]
//public ServicePrice CurrentPrice { get; set; }
}
}
Test Data:
using (var db = container.Resolve<IDbConnectionFactory>().Open())
{
db.DropAndCreateTable<MyNamespace.Visit>();
db.DropAndCreateTable<MyNamespace.VisitService>();
db.DropAndCreateTable<MyNamespace.Service>();
var visitId = db.Insert(new MyNamespace.Visit {
Date = DateTime.UtcNow, Notes = "Notes"}, selectIdentity: true);
var serviceId = (int)db.Insert(new MyNamespace.Service {
ServiceTypeId = 1, Name = "Name"}, selectIdentity:true);
db.Insert(new MyNamespace.VisitService {
VisitId = visitId, ServiceId = serviceId, Quantity = 1});
}
Service Result:
http://localhost:{port}/visits/1/services.json
JSON Response:
{
offset: 0,
total: 1,
results: [{
serviceTypeId: 1,
name: "Name",
displayOrder: 0,
isHourly: false,
isMonthly: false,
visitId: 1,
serviceId: 1,
quantity: 1,
feeIsWaived: false
}]
}

automapper Missing type map configuration or unsupported mapping

I'm trying to map the following entities:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Address Address { get; set; }
public DateTime DOB { get; set; }
public List<Telephone> Telephones { get; set; }
}
public class SearchPersonViewModel
{
public int Id { get; set; }
public string FullName { get; set; }
public string LicencePlate { get; set; }
public string CarMake { get; set; }
public string CarModel { get; set; }
}
I do that:
AutoMapper.Mapper.CreateMap<List<SearchPersonViewModel>, List<Person>>();
List<SearchPersonViewModel> model = AutoMapper.Mapper.Map<List<Person>, List<SearchPersonViewModel>>(persons);
And I get the exception 'Missing type map configuration or unsupported mapping.'
I don't see what's wrong with my code, anyone could help ?

Resources