Reputation: 23
I have a problem with mapping in AutoMapper.
I try use ForMember function, but still get a error connecting with mapping.
How to CreateMap for this Entities?
I created a AutoMapping class:
public class AutoMapping : Profile
{
public AutoMapping()
{
CreateMap<Member, MemberDto>()
.ForMember(dest => dest.Groups, opt => { opt.MapFrom(src => src.GroupMember.Select(x => x.Group)); });
CreateMap<Group, GroupDto>()
.ForMember(dest => dest.Members, opt => { opt.MapFrom(src => src.GroupMember.Select(x => x.Member)); });
}
}
And I tried use it like this:
public async Task<Page<MemberDto>> GetPaginatedAsync(IDataTablesRequest request)
{
Filters<MemberDto> filters = GetFiltersFromRequest(request);
Sorts<MemberDto> sorts = GetSortsFromRequest(request);
var currentPage = request.Start / request.Length + 1;
var pageSize = request.Length;
try
{
return await _context.Member
.Include(gm => gm.GroupMember)
.ThenInclude(g => g.Group)
.Select(m => _mapper.Map<MemberDto>(m))
.PaginateAsync(currentPage, pageSize, sorts, filters);
}
catch (Exception ex)
{
throw ex; //Log it
}
}
In next steps I will make the same with rest of my Entities, but please give me some tips :)
EDIT: After use
.ProjectTo<MemberDto>(_mapper.ConfigurationProvider)
.PaginateAsync(currentPage, pageSize, sorts, filters);
I get error like
The LINQ expression 'DbSet<Member>
.Where(m => DbSet<GroupMember>
.Where(g => EF.Property<Nullable<int>>(m, "MemberId") != null && EF.Property<Nullable<int>>(m, "MemberId") == EF.Property<Nullable<int>>(g, "MemberId"))
.Join(
outer: DbSet<Group>,
inner: g => EF.Property<Nullable<int>>(g, "GroupId"),
outerKeySelector: g0 => EF.Property<Nullable<int>>(g0, "GroupId"),
innerKeySelector: (o, i) => new TransparentIdentifier<GroupMember, Group>(
Outer = o,
Inner = i
))
.Select(g => new GroupDto{
CreatedDate = g.Inner.CreatedDate,
DeletedDate = g.Inner.DeletedDate,
GroupId = g.Inner.GroupId,
IsActive = g.Inner.IsActive,
Members = DbSet<GroupMember>
.Where(g1 => EF.Property<Nullable<int>>(g.Inner, "GroupId") != null && EF.Property<Nullable<int>>(g.Inner, "GroupId") == EF.Property<Nullable<int>>(g1, "GroupId"))
.Join(
outer: DbSet<Member>,
inner: g1 => EF.Property<Nullable<int>>(g1, "MemberId"),
outerKeySelector: m0 => EF.Property<Nullable<int>>(m0, "MemberId"),
innerKeySelector: (o, i) => new TransparentIdentifier<GroupMember, Member>(
Outer = o,
Inner = i
))
.Select(g1 => new MemberDto{
CreatedDate = g1.Inner.CreatedDate,
DateOfBirth = g1.Inner.DateOfBirth,
Email = g1.Inner.Email,
FirstName = g1.Inner.FirstName,
IsActive = g1.Inner.IsActive,
LastName = g1.Inner.LastName,
MemberId = g1.Inner.MemberId,
PhoneNumber = g1.Inner.PhoneNumber,
UpdatedDate = g1.Inner.UpdatedDate
}
)
.ToList(),
Name = g.Inner.Name,
UpdatedDate = g.Inner.UpdatedDate
}
)
.ToList()
.Any(g => g.Name.Contains(__column_Search_Value_0)))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
EDIT2: I use it for Paginate and Filtering:
https://github.com/wdunn001/EntityFrameworkPaginateCore/tree/master/EntityFrameworkPaginateCore
EDIT3:
private static Sorts<MemberDto> GetSortsFromRequest(IDataTablesRequest request)
{
var sorts = new Sorts<MemberDto>();
foreach (var column in request.Columns.Where(x => x.IsSortable && x.Sort != null))
{
switch (column.Field)
{
case "firstName":
sorts.Add(true, x => x.FirstName, column.Sort.Direction != SortDirection.Ascending);
break;
case "lastName":
sorts.Add(true, x => x.LastName, column.Sort.Direction != SortDirection.Ascending);
break;
case "email":
sorts.Add(true, x => x.Email, column.Sort.Direction != SortDirection.Ascending);
break;
case "phoneNumber":
sorts.Add(true, x => x.PhoneNumber, column.Sort.Direction != SortDirection.Ascending);
break;
default:
break;
}
}
return sorts;
}
private static Filters<MemberDto> GetFiltersFromRequest(IDataTablesRequest request)
{
var filters = new Filters<MemberDto>();
foreach (var column in request.Columns
.Where(x => x.IsSearchable && x.Search != null &&
!string.IsNullOrWhiteSpace(x.Search.Value))
)
{
switch (column.Field)
{
case "firstName":
filters.Add(true, x => x.FirstName.Contains(column.Search.Value));
break;
case "lastName":
filters.Add(true, x => x.LastName.Contains(column.Search.Value));
break;
case "email":
filters.Add(true, x => x.Email.Contains(column.Search.Value));
break;
case "phoneNumber":
filters.Add(true, x => x.PhoneNumber.Contains(column.Search.Value));
break;
case "groups":
filters.Add(true, x => x.Groups.Any(g => g.Name.Contains(column.Search.Value)));
break;
default:
break;
}
}
return filters;
}
EDIT4:
CreateMap<Member, MemberDto>()
.ForMember(dest => dest.Groups,
opt => { opt.MapFrom(src => src.GroupMember); });
After removing SELECT I get a error:
Missing map from CMSport.Context.Models.GroupMember to CMSport.Dto.GroupDto. Create using CreateMap<GroupMember, GroupDto>.
SOLUTION:
1. Make filter and sorts by Member, not by MemberDto
2. Set Dtos as [JsonObject(IsReference = true)]
3. Map it after PaginateAsync like this
var page = await _context.Member
.Include(x => x.GroupMember)
.ThenInclude(x => x.Group)
.PaginateAsync(currentPage, pageSize, sorts, filters);
return new Page<MemberDto>
{
CurrentPage = page.CurrentPage,
PageCount = page.PageCount,
PageSize = page.PageSize,
RecordCount = page.RecordCount,
Results = page.Results.Select(x => _mapper.Map<MemberDto>(x))
};
Upvotes: 0
Views: 903
Reputation: 1148
I suppose that you have an error related to translating LINQ
to SQL
, in the
.Select(m => _mapper.Map<MemberDto>(m))
Obviously, _mapper.Map<MemberDto>(m)
can't be translated to SQL
, therefore instead of that line you can try to use .ProjectTo<MemberDto>()
(see QuarableExtensions) so that the query will look like
return await _contesnxt.Member
.ProjectTo<MemberDto>()
.PaginateAsync(currentPage, pageSize, sorts, filters);
Upvotes: 1