Automapper Not mapped list dto to list - c#

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; }
}

Related

EF Include is not working! returning null in a 1 to many relationship

i am trying to display a list of cities with a country, a 1 to many relation.
I created the models for both of them:
City model
[Key]
public int ID_Cidade { get; set;
public int ID_Pais { get; set; }
public RH_Pais Pais { get; set; }
public string Nome { get; set; }
public Boolean Capital { get; set; }
public DateTime SysStartTime { get; set; }
public DateTime SysEndTime { get; set; }
public string Autor { get; set; }
public int OrdemCidade { get; set; }
public List<RH_Escritorios> Escritorios { get; set; }
Country model
[Key]
public int ID_Pais { get; set; }
public int ID_Moeda { get; set; }
public RH_Moeda Moeda { get; set; }
public string Nome { get; set; }
public string Nome_completo { get; set; }
public DateTime SysStartTime { get; set; }
public DateTime SysEndTime { get; set; }
public string Autor { get; set; }
public int OrdemPais { get; set; }
public List<RH_Cidades> Cidades { get; set; }
public List<RH_Idioma_Pais> Idiomas { get; set; }
and then i used fluent API to create the relationship
modelBuilder.Entity<RH_Cidades>()
.HasOne(m => m.Pais)
.WithMany(m => m.Cidades)
.HasForeignKey(m => m.ID_Pais);
and somehow when i generate the controller with EF, and i go to see the cities it causes a null error... this is because it has a include of the country when im trying to get the cities..
var rH_EntitiesContext = _context.RH_Cidades.Include(r => r.Pais).ToList();
The most annoying part is that i have the exact same situation in another relationship, with 1 to many and the include and it works perfectly!!
I have read and read my code for hours by now and i cannot see why the Include is giving me that error when in the offices controller with the same situation works...
Any help is appreciated!!!

How to fix Entity Framework Core "Argument types do not match" with Linq Select projection

When attempting a straight forward projection using Entity Framework Core and Linq, I am getting an "Argument types do not match" exception.
I have looked into possible causes and have narrowed it down to the Select that is causing the error (see below). There is a GitHub issue describing a similar situation with simple types and optional navigation entities, but none of the suggested solutions have worked for me. It is not a nullable type and I have tried casting or using Value on any child properties. I have also tried setting the relationship to required in the DbContext which isn't exactly ideal.
Here is the Linq query in the repository:
return await _dashboardContext.PresetDashboardConfig
.Where(config => config.DashboardTypeId == dashboardType && config.OrganisationType = organisationType)
.GroupBy(config => config.GroupId)
.Select(config => new DashboardConfigDTO
{
DashboardType = config.First().DashboardTypeId,
OrganisationId = organisationId,
WidgetGroups = config.Select(group => new WidgetGroupDTO
{
Id = group.Id,
Name = group.GroupName,
TabOrder = group.TabOrder,
// Problem Select below:
Widgets = group.Widgets.Select(widget => new WidgetConfigDTO
{
IndicatorId = widget.IndicatorId,
ScopeId = widget.ScopeId.ToString(),
ParentScopeId = widget.ParentScopeId.ToString(),
WidgetType = widget.WidgetType,
WidgetSize = widget.WidgetSize,
Order = widget.Order
})
})
})
.SingleOrDefaultAsync();
And the entities:
public class DashboardConfig
{
public int Id { get; set; }
public int DashboardTypeId { get; set; }
public int OrganisationType {get; set; }
public int GroupId { get; set; }
public string GroupName { get; set; }
public int TabOrder { get; set; }
}
public class PresetDashboardConfig : DashboardConfig
{
public ICollection<PresetWidgetConfig> Widgets { get; set; }
}
public class WidgetConfig
{
public int Id { get; set; }
public int IndicatorId { get; set; }
public long ScopeId { get; set; }
public long? ParentScopeId { get; set; }
public int WidgetType { get; set; }
public int WidgetSize { get; set; }
public int Order { get; set; }
}
public class PresetWidgetConfig : WidgetConfig
{
public int PresetDashboardConfigId { get; set; }
}
And finally, the DbContext ModelBuilder:
modelBuilder.Entity<PresetDashboardConfig>(entity =>
{
entity.Property(e => e.GroupName)
.HasMaxLength(32)
.IsUnicode(false);
entity.HasMany(e => e.Widgets)
.WithOne();
});
Below are the DTO classes as per Henk's comment:
public class DashboardConfigDTO
{
public int DashboardType { get; set; }
public int OrganisationId { get; set; }
public IEnumerable<WidgetGroupDTO> WidgetGroups { get; set; }
}
public class WidgetGroupDTO
{
public int Id { get; set; }
public string Name { get; set; }
public int TabOrder { get; set; }
public IEnumerable<WidgetConfigDTO> Widgets { get; set; }
}
public class WidgetConfigDTO
{
public int IndicatorId { get; set; }
public string ScopeId { get; set; }
public string ParentScopeId { get; set; }
public int WidgetType { get; set; }
public int WidgetSize { get; set; }
public int Order { get; set; }
}

Automapper - Unable to map nested objects/collecions

I've tried numerous examples on here and from the automapper wiki and I am still unable to get this issue resolved. I am trying to map a nested object and a nested collection and no matter what I do it always throws an error. The only way I can get the controller to return data is by turning on option.ignore for the two properties.
These are the business layer objects I am trying to map
public class LocationBL
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zipcode { get; set; }
public string Country { get; set; }
public DbGeography Coordinates { get; set; }
public int LocationType_Id { get; set; }
public virtual LocationTypeBL LocationType { get; set; }
public virtual ICollection<SportBL> Sports { get; set; }
}
public class LocationTypeBL
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<LocationBL> Locations { get; set; }
}
public class SportBL
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<LocationBL> Locations { get; set; }
public virtual ICollection<UserBL> Users { get; set; }
}
These are the data layer objects
public class Location : EntityData
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[ForeignKey("Company")]
public int? CompanyId { get; set; }
[Required]
public string Name { get; set; }
public string Address { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zipcode { get; set; }
public string Country { get; set; }
[Required]
public DbGeography Coordinates { get; set; }
[ForeignKey("LocationType")]
public int LocationType_Id { get; set; }
public virtual LocationType LocationType { get; set; }
public virtual ICollection<Sport> Sports { get; set; }
public virtual Company Company { get; set; }
}
public class LocationType : EntityData
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Location> Locations { get; set; }
}
public class Sport : EntityData
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<Location> Locations { get; set; }
public virtual ICollection<User> Users { get; set; }
}
This is my mapping profile
public class LocationProfile : Profile
{
public LocationProfile()
{
CreateMap<LocationType, LocationTypeBL>();
CreateMap<LocationTypeBL, LocationType>();
CreateMap<Location, LocationBL>()
.ForMember(Dest => Dest.Sports,
opt => opt.MapFrom(src => src.Sports))
.ForMember(Dest => Dest.LocationType,
opt => opt.MapFrom(src => src.LocationType));
CreateMap<LocationBL, Location>()
.ForMember(Dest => Dest.Sports,
opt => opt.MapFrom(src => src.Sports))
.ForMember(Dest => Dest.LocationType,
opt => opt.MapFrom(src => src.LocationType));
}
}
UPDATE *******
This is my LocationType profile
public class LocationTypeProfile : Profile
{
public LocationTypeProfile()
{
CreateMap<LocationType, LocationTypeBL>();
CreateMap<LocationTypeBL, LocationType>();
}
}
This is my Sport profile
public class SportProfile : Profile
{
public SportProfile()
{
CreateMap<Sport, SportBL>();
CreateMap<SportBL, Sport>();
}
}
Not sure if it matters but this is an Azure Mobile App backend using Autofac, WebAPI, and OWIN. This is my first time using AutoMapper and Autofac so please forgive me as I am still learning. The profiles are all registered and if I set the nested objects to ignore, the controller returns the proper data.
Thank you in advance!!!
You are almost there. You need to instruct AutoMapper on how to map the nested objects as well. So you need to create a map for the Sport to SportBL, and vice-versa, also.
// use ForMember if needed, but you know how to do that so I won't
// show it.
CreateMap<Sport, SportBL>();
Then AutoMapper will use that mapping when it mapping nested complex types.
Another note, if your classes have the same properties, you can just call the ReverseMap() method and it will do bidirectional mapping for you.
So instead of this:
CreateMap<LocationType, LocationTypeBL>();
CreateMap<LocationTypeBL, LocationType>();
You can just do this to accomplish the same thing:
Mapper.CreateMap<LocationType, LocationTypeBL>().ReverseMap();

The member with identity 'PmData.SafetyRequirement_Assets' does not exist in the metadata collection.\r\nParameter name: identity

I am trying to update an record in my system. Everything on the model saves great, except any of my many to many type relationships on the form. When I get to those in my model it gives me the error. "The member with identity 'PmData.SafetyRequirement_Assets' does not exist in the metadata collection.\r\nParameter name: identity". I've read over some of the other answers but I do not have any triggers on my database, and I've gone through several changes in my model based on other suggestions and it doesn't seem to change anything. The project is in vNext.
Here is my first model
public partial class Asset : DataModel
{
[Required]
[StringLength(64)]
public string Name { get; set; }
[StringLength(256)]
public string Description { get; set; }
[StringLength(1024)]
public string SystemFunction { get; set; }
[StringLength(2048)]
public string Remarks { get; set; }
public bool IsSystem { get; set; }
public bool IsGrouping { get; set; }
[StringLength(128)]
public string FieldTag { get; set; }
[ForeignKey("Parent")]
public int? ParentId { get; set; }
[ForeignKey("Building")]
public int? BuildingId { get; set; }
public bool IsOperable { get; set; }
public bool IsAvailable { get; set; }
public virtual Asset Parent { get; set; }
public virtual Building Building { get; set; }
public virtual ICollection<Asset> Children { get; set; }
public virtual ICollection<DrawingReference> DrawingReferences { get; set; }
public virtual ICollection<SpecReference> SpecReferences { get; set; }
public virtual ICollection<SafetyRequirement> SafetyRequirements { get; set; }
public virtual ICollection<SupportSystem> SupportSystems { get; set; }
}
The model for one the other table with a many to many.
public partial class SafetyRequirement : DataModel
{
[StringLength(256)]
[Required]
public string Name { get; set; }
[StringLength(2048)]
public string SafetyFunction { get; set; }
[StringLength(2048)]
public string FunctionalRequirements { get; set; }
[StringLength(2048)]
public string SystemBoundary { get; set; }
[StringLength(255)]
public string Reference { get; set; }
[ForeignKey("QualityLevel")]
public int QualityLevelId { get; set; }
public virtual QualityLevel QualityLevel { get; set; }
public virtual ICollection<Asset> Assets { get; set; }
}
The map for the joining table
modelBuilder.Entity<Asset>().HasMany(t => t.SafetyRequirements)
.WithMany(t => t.Assets)
.Map(m =>
{
m.MapRightKey("SafetyRequirementId");
m.MapLeftKey("AssetId");
m.ToTable("AssetSafetyRequirement");
});
Finally here's the area that it fails...
public virtual void SaveAsync(TEntity model)
{
Task.Run(() =>
{
using (
var dbContext =
(TContext)
Activator.CreateInstance(typeof (TContext),
ConfigOptions == null ? ConfigService.ConnectionString : ConfigOptions.ConnectionString))
{
var dbSet = dbContext.Set<TEntity>();
dbSet.Attach(model);
dbContext.Entry(model).State = EntityState.Modified;
dbContext.SaveChanges();
}
});
}
Any information or pointers would be greatly appreciated.
You're trying to use both Fluent API and Data Annotations to define the relationships between your tables. Remove one or the other.

Property of one type map to another type of instance

I am using automapper for mapping view models and entity models with each other, all was good, but now i have a little different scenario where AutoMapper is not able to map my types.
My View Model:
public class CriminalSearchViewModel
{
public CriminalSearchParamsViewModel SearchParameters { get; set; }
public SelectList GenderSelectList { get; set; }
public SelectList NationalitySelectList { get; set; }
public SelectList CrimeSelectList { get; set; }
public SelectList CriminalStatusSelectList { get; set; }
}
second view model:
public class CriminalSearchParamsViewModel
{
[Required]
public string FirstName { get; set; }
public string LastName { get; set; }
public int? GenderID { get; set; }
public int? StatusID { get; set; }
public string CNIC { get; set; }
public int? AgeFrom { get; set; }
public int? AgeTo { get; set; }
public double? Height { get; set; }
public int Weight { get; set; }
public int? NationalityID { get; set; }
}
and my Business Model:
public class CriminalSearch
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int? GenderID { get; set; }
public int? StatusID { get; set; }
public string CNIC { get; set; }
public int? AgeFrom { get; set; }
public int? AgeTo { get; set; }
public double? Height { get; set; }
public int Weight { get; set; }
public int? NationalityID { get; set; }
}
I have defined mapping like:
Mapper.CreateMap<CriminalSearch, CriminalSearchParamsViewModel>();
also tried this as well:
Mapper.CreateMap<CriminalSearchParamsViewModel,CriminalSearchViewModel>()
.ForMember(dest => dest.SearchParameters, opt =>
opt.MapFrom(src => Mapper.Map<CriminalSearchParamsViewModel, CriminalSearch>(src)));
and in controller i am trying like:
public ActionResult Search(CriminalSearchViewModel searchVM)
{
if (ModelState.IsValid)
{
var searchParams = searchVM.SearchParameters;
var criminalSearch = AutoMapper.Mapper.Map<CriminalSearch>(searchParams);
_criminalService.SearchCriminals(criminalSearch);
}
return View();
}
But it always throws exception:
Missing type map configuration or unsupported mapping.
Mapping types:
CriminalSearchParamsViewModel -> CriminalSearch
NationalCriminals.UI.ViewModels.CriminalSearchParamsViewModel -> NationalCriminals.Core.Models.CriminalSearch
Destination path:
CriminalSearch
Source value:
NationalCriminals.UI.ViewModels.CriminalSearchParamsViewModel
Anybody can pint me what is going wrong?
You just need to change the order of the generic args in the method CreateMap:
Mapper.CreateMap<CriminalSearchParamsViewModel,CriminalSearch>()
Thats because the first generic arg is the Source type and the second is the Destination, it is not two way, you must to declare the both if you want to map from a type to another and viceversa like this:
Mapper.CreateMap<CriminalSearchParamsViewModel,CriminalSearch>()
Mapper.CreateMap<CriminalSearch,CriminalSearchParamsViewModel>()
The method CreateMap is described like this:
AutoMapper.Mapper.CreateMap<SourceClass, DestinationClass>();
Suggest: Using AutoMapper: Creating Mappings

Categories