'Map nested object with Automapper in C#
I use the latest version of AutoMapper 10.1.1 in my .NET Core project. I have a simple database for learning new words in a language I want to learn. I have the following tables:
- Words
- WordExamples
- WordExampleTranslation
In Words there is an ID for the word, and in the WordExamples I refer to this ID to link an example for that word. In WordExampleTranslation I have a reference to the ID of WordExamples to have a translation in my language (just to understand what the example means). Every table has a lot of columns such as CreatedAt, CreatedBy and so on.
With Entity Framework Core, I read this data based on the word ID and I want to return to the UI only the essential fields.
public IQueryable<WordExample> GetAllByWordId(long wordId)
{
return _db.WordExamples
.Include(c => c.Word)
.Include(c => c.Translations)
.Where(r => r.WordId == wordId);
}
For that, I created 2 classes for basic information
public class BaseWordExample
{
public long LanguageId { get; set; }
public long WordId { get; set; }
public string Example { get; set; }
public IEnumerable<BaseWordExampleTranslation> Translations { get; set; }
}
public class BaseWordExampleTranslation
{
public long LanguageId { get; set; }
public long WordId { get; set; }
public long DestinationLanguageId { get; set; }
public string TraslationExample { get; set; }
}
Then, I have my MappingProfile
for AutoMapper
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<WordExample, BaseWordExample>()
.ReverseMap();
CreateMap<WordExampleTranslation, BaseWordExampleTranslation>()
.ReverseMap();
}
}
Then, I have an API
public async Task<IActionResult> GetAllAsync(long wordId)
{
var list = _localDb.GetAllByWordId(wordId);
var model = _mapper.Map<List<BaseWordExample>>(list);
return model != null ? Ok(model) : NotFound();
}
I expect to receive a json mapped to the basic classes with all the data from WordExamples and also from its dependency table WordExampleTranslation. What I have is only the WordExamples values. The field Translations is not recognized by AutoMapper.
[
{
"id": 1,
"language": 5,
"wordId": 1,
"example": "Eu parto para Inglaterra",
"exampleHtml": "<i>Eu</i> <b>parto</b> para Inglaterra"
}
]
Then, I tried to change the MappingProfile
like the following
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<WordExample, BaseWordExample>()
.ForMember(dest => dest.Translations,
act => act.MapFrom(src => src.Translations))
.ReverseMap();
CreateMap<WordExampleTranslation, BaseWordExampleTranslation>()
.ReverseMap();
}
}
but in this case I get this error
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.MissingMethodException: Method not found: 'System.Collections.Generic.IEnumerable`1<WB.Domain.Base.BaseWordExampleTranslation> WB.Domain.Base.BaseWordExample.get_Translations()'.
Update: I tried to convert the IQueryable
result in a list
var list = _localDb.GetAllByWordId(wordId).ToList();
and then use Mapper but, again, I have only the main object. All the data from the dependency table WordExampleTranslation are ignored.
Solution 1:[1]
Try this one
public async Task<IActionResult> GetAllAsync(long wordId)
{
var list = _localDb.GetAllByWordId(wordId);
var model = _mapper.Map<List<BaseWordExample>, List<WordExample>>(list);
return model != null ? Ok(model) : NotFound();
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | ggeorge |